Change:
composerRepositoryHook = makeSetupHook { name = "composer-repository-hook.sh"; <del> propagatedBuildInputs = [ jq moreutils php cacert ]; </del> <ins> propagatedBuildInputs = [ jq moreutils cacert ]; </ins> substitutions = { }; } ./composer-repository-hook.sh; composerInstallHook = makeSetupHook { name = "composer-install-hook.sh"; <del> propagatedBuildInputs = [ jq makeBinaryWrapper moreutils php cacert ]; </del> <ins> propagatedBuildInputs = [ jq makeBinaryWrapper moreutils cacert ]; </ins> substitutions = { # Specify the stdenv's `diff` by abspath to ensure that the user's build # inputs do not cause us to find the wrong `diff`.

Discussion:
I might be misunderstanding, but I believe that there's a bug in (or below), since I don't get the I expect in my build script. Try to build the following: inside the derivation should be the same as , and should succeed.
While trying to understand this issue, I found another one and I fixed it here:
I've been testing this quickly before work and I noticed that the builder works as expected. Here's a new derivation to show you: In that derivation, the has been modified, and I just in the section. What can we notice? in the original example is wrong, my example derivation as it is, just works, you replace by , you can notice that you are not able to build it any more. This is a proof that the builder is using the proper PHP version when installing the application.
Thanks for taking a look, and for reminding me about adding extensions in . That's strange, I produced it by setting it to and substituting as usual. I cannot verify your claim. Yes, I can confirm that the derivation you posted builds on my machine. Yes, I observe the same. I do not agree. Your derivation does not print/check paths of the executables, and it also does not invoke . I expect both paths to be the same, or have an explanation for why they are different, and I expect to succeed. Merging the following into your derivation... ... produces ... on my machine. So I unfortunately cannot accept your proof.

Taking your hint about I improve my counterexample, which I expect to build but it does not: <details<pre{ lib, php, runCommand, which }: let phpWithExtensions = php.withExtensions ({ enabled, all }: enabled ++ []); in phpWithExtensions.buildComposerProject (finalAttrs: { pname = "test"; version = "0.0.1"; src = runCommand "test" {} '' mkdir -p $out echo """ { "name": "test/test", "description": "test", "license": "GPL-3.0-or-later", "require": { "ext-redis": "" } } """ $ echo """ { "_readme": [ "This file locks the dependencies of your project to a known state", "Read more about it at ", "This file is automatically" ], "content-hash": "", "packages": [], "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { "ext-redis": "*" }, "platform-dev": [], "plugin-api-version": "2.6.0" } """ $ ''; vendorHash = "sha256-Ib7cuatJ8iBSEGDvs1QgvOzV2XXI9Pxb7elyQgAR+kY="; nativeBuildInputs = [ which ]; buildPhase = '' # The following two lines are different?! echo (which php)) echo ${lib.getExe phpWithExtensions} echo ${lib.getExe php} # Missing extension is how I discovered this bug. php --ri redis ''; }) </pre</detailsThe only explanation I have so far, is that Composer uses a different PHP than what is on the in the build phase...
I think I've found the source of the confusion. was right. My mistake. The problem with is in your . You're basically calling the derivation introduced on . I'm pretty sure that those needs to be removed from line 15 and line 22 ( : what's your point of view on this?) Removing those derivation from the hooks - or providing the same as the one calling would be a better option here. So basically, the builder was using the proper PHP version, but the phases were using the wrong one from the hooks.

I found that with the following change, will use the correct PHP:
I think that's a very good solution indeed. Good catch! Do you mind sending a pull-request to fix this in , and in the hooks ?
Expect a PR soon.