Skip to content

php-ci/phpstan action: php-version never reaches PHPStan, so the matrix analyses every entry at the composer platform level #53

Description

@mattgoud

Summary

.github/actions/php-ci/phpstan/action.yml passes its php-version input to shivammathur/setup-php, and nowhere else. PHPStan never receives it, so it takes the PHP language level it analyses with from the analysed project's composer platform declaration instead.

The consequence is that the php_version dimension of every module matrix has no effect on the analysis. All entries analyse the same code at the same language level, whatever PHP binary they run on.

Evidence

Measured against a PrestaShop 9.2.0 core with ps_emailsubscription, reproducing the action's own steps (ps-module-extension.neon merged with the module config, level 5).

The analysis ran on the PHP 8.3.6 binary and still reported:

Call to method getLanguages() on an unknown class
PrestaShop\PrestaShop\Core\Context\LegacyControllerContext.

That error can only occur below PHP 8.0: LegacyControllerContext uses constructor property promotion, readonly and union types, so PHPStan cannot parse it and treats it as an unknown class. The module declares config.platform.php: 7.1.0, and that is the level PHPStan used, not the 8.3 it was executing on.

Same file, same core, only the neon changed:

Configuration Result
no phpVersion 3 errors, unknown class
phpVersion: 80100 no errors

So the level is entirely decided by the config and the composer platform, never by php-version.

Why it matters

This is not theoretical. A cast helper was added to three native modules purely to silence that unknown-class error, which is a symptom of the wrong analysis level rather than a code problem. In ps_wirepayment the helper carried a native : AdminController return type and produced a fatal error on the configuration page of every PrestaShop 9.x shop, with all fourteen static jobs green. See PrestaShop/ps_wirepayment#103.

Modules are currently working around this one by one, by pinning phpVersion in their own 9.x neon files:

Those are interim fixes for something that belongs in the shared action.

Proposal

The action already builds phpstan-temp.neon on the fly. Deriving phpVersion from the php-version input and appending it there fixes every module at once, and makes the matrix mean what it appears to mean:

# php-version "8.1" -> 80100
PHP_VERSION_ID=$(echo "${{ inputs.php-version }}" | awk -F. '{ printf "%d%02d00", $1, $2 }')
{
  echo "parameters:"
  echo "  phpVersion: $PHP_VERSION_ID"
} >> "$TEMP_CONFIG"

Two things to settle before implementing:

  1. Collision with module-level pins. Several modules now set phpVersion in their own neon, which the temp config includes alongside the injected value. Whether the include wins, the inline value wins, or neon raises a duplicate-key error needs checking, and the module pins should be removed once the action handles it.
  2. An opt-out. An input such as phpstan-php-version defaulting to the php-version value, so a module can still pin a different analysis level deliberately.

Not usable yet: the version range

PHPStan supports phpVersion as a {min, max} range, which would let one run cover the whole supported interval and would allow shrinking the matrix. It is not available across the board today:

phpVersion: {min: 80100, max: 80500}
  -> Invalid configuration: 'parameters › phpVersion' expects to be int|null, array given
Core analysed PHPStan shipped
8.2.x, 9.0.3, 9.1.5, 9.2.x ^1.9.3, resolves to 1.12.x
develop ^2.2

The action takes PHPStan from the analysed core when one is present, so the range only works on the develop entry for now. Worth revisiting when the 9.x branches move to PHPStan 2.

Related

Modules cleanup epic PrestaShop/PrestaShop#41648, which is the campaign that surfaced this.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions