fix: suppress always-true PHPStan narrowing on Composer tryComposer guard#84
Conversation
…uard CommandContextTrait guards `tryComposer()` (Composer >=2.3) behind `method_exists($this, 'tryComposer')` so the deprecated getComposer() path still works on Composer 2.2 LTS (composer.json: "2.2.*|^2.9"). PHPStan analyses against the highest resolved Composer, where the method always exists, and reports function.alreadyNarrowedType once per command class using the trait. The inline @phpstan-ignore-next-line did not match all per-class trait analyses, so the check became red once the highest Composer (>=2.3) was resolved (no committed lock file). Move the suppression to a path-scoped ignoreErrors entry in phpstan.neon (reportUnmatched: false) and drop the ineffective inline ignore. The runtime guard is unchanged and still required for the 2.2.* support path. Fixes the Code Quality job, which is red on main under current resolution. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
There was a problem hiding this comment.
Code Review
This pull request moves the PHPStan suppression for the function.alreadyNarrowedType error from an inline comment in src/Commands/CommandContextTrait.php to a path-scoped ignore in phpstan.neon. This ensures that the runtime guard checking for the existence of tryComposer (which is required for Composer 2.2 LTS compatibility but flagged as always-true when analyzed against Composer >=2.3) is correctly suppressed across all command classes that consume the trait. There are no review comments, so I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
There was a problem hiding this comment.
Pull request overview
This PR fixes a PHPStan false-positive on main caused by PHPStan analyzing against the highest resolved Composer version (where tryComposer() always exists), while the code intentionally retains a runtime guard for Composer 2.2 LTS compatibility.
Changes:
- Replaces an ineffective inline
@phpstan-ignore-next-linewith a path-scopedignoreErrorsrule inphpstan.neonforfunction.alreadyNarrowedType. - Updates inline comments in
CommandContextTrait::resolveContext()to document where/why the suppression is configured.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/Commands/CommandContextTrait.php | Removes the inline PHPStan suppression and points maintainers to the centralized suppression in config. |
| phpstan.neon | Adds a path-scoped ignoreErrors entry (with rationale) to suppress the Composer-version-dependent narrowing false positive. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.



Problem
Code Quality(PHPStan) is red onmainunder current dependency resolution — confirmed by re-running the last-green run (26959408575). This is independent of any workflow change; it's no-committed-lockfile drift.CommandContextTrait::resolveContext()guardstryComposer()(Composer ≥2.3) behindmethod_exists($this, 'tryComposer')so the deprecatedgetComposer()path still works on Composer 2.2 LTS — whichcomposer.jsonexplicitly supports ("composer/composer": "2.2.*|^2.9", and the CI matrix tests 2.2). PHPStan analyses against the highest resolved Composer (2.10.1), wheretryComposer()always exists, so it reportsfunction.alreadyNarrowedType— once per command class that uses the trait (5 errors). The inline@phpstan-ignore-next-linedoes not match all per-class trait analyses, so it stopped suppressing them.Fix
ignoreErrorsentry inphpstan.neon(identifierfunction.alreadyNarrowedType,reportUnmatched: false) — robust across the trait's per-class analyses.Verification
Local, fresh highest resolution (
composer/composer2.10.1, PHPStan 2.2.2, PHP 8.5):[OK] No errors(was 5 errors before).Context
Surfaced while migrating CI to the org reusable
php-ci.yml(#83) — that PR'sChecksjob runs PHPStan and inherited this pre-existing failure. This fix is split out so it stands on its own and unblocksmain.