grumphp icon indicating copy to clipboard operation
grumphp copied to clipboard

Composer plugin tasks not executed using the PHP version Composer is invoked with

Open echernyavskiy opened this issue 8 months ago • 4 comments

Given:

  • two PHP versions installed side by side - 8.2 and 8.3
  • /usr/bin/php invokes PHP 8.2 (managed via alternatives), so that's the default version
  • Composer is explicitly invoked with PHP 8.3, i.e. /usr/bin/php8.3 ./composer.phar install

In this setup GrumPHP git:init and configure scripts are executed using PHP 8.2 because the plugin calls vendor/bin/grumphp directly instead of using the PHP binary Composer is using for the current invocation.

I'm not familiar with Composer Plugin API enough to tell if Composer exposes internally the PHP binary it was invoked with. However it looks like there is @php syntax for scripts that does something similar to what ${MAKE} would do in a Makefile, so Composer must maintain some sort of reference to the current PHP binary.

echernyavskiy avatar Apr 11 '25 06:04 echernyavskiy

Thanks for reporting @echernyavskiy.

The composer plugin is currently indeed not taking into account what PHP version you are executing with. See https://github.com/phpro/grumphp/blob/d6ba4be604db16a4a3fc0d2fc505c0667bbe95c4/src/Composer/GrumPHPPlugin.php#L210 on how this works.

Care to take a dive into the code and craft a PR that fixes this?

veewee avatar Apr 11 '25 08:04 veewee

@veewee, yeah, that's the file I was looking at, and that's how I arrived at the conclusion above. Any pointers on how to approach this? Like I said I'm not familiar with the Composer Plugin API.

echernyavskiy avatar Apr 11 '25 08:04 echernyavskiy

@echernyavskiy It boils down to scrolling through the files in composer/composer.

  • vendor/composer/composer/src/Composer/EventDispatcher/EventDispatcher.php
  • getPhpExecCommand()
  • It seems to be just using '\Symfony\Component\Process\PhpExecutableFinder' (but with additional logic)

The plugin has been created a long way back. Since then, composer has changed a lot. it might make sense to re-evaluate how it works at some point. Here's for example a snippet on how it could be done by using composer dependencies only:

$composer = $event->getComposer();
$loop = $composer->getLoop();
$command_executor = $loop->getProcessExecutor();

$command_executor->executeTty(implode(' ', [
    (new PhpExecutableFinder())->find(),
    ...array_map(static fn(string $argument): string => ProcessExecutor::escape($argument), [
        $this->detectGrumphpExecutable(),
        'arg...'
    ]),
]));

Full example

(it should probably contain some additional logic for Windows and .exe support)

veewee avatar Apr 11 '25 08:04 veewee

@veewee from what I can tell PhpExecutableFinder already handles PHP on Windows, so my PR is pretty concise: #1171.

echernyavskiy avatar Apr 15 '25 16:04 echernyavskiy