Add a dynamic return type extension for wp_parse_args() (2.x) - #310
Conversation
Port of the extension merged into the 1.x line (master) to the 2.x line for PHPStan 2. The extension itself is unchanged; the type assertions that depend on PHPStan 2 internals are kept in a separate data file gated on PHPStan 2.1.39, in line with the existing slashit gate: - PHPStan 2.1.1 normalizes unions of array shapes differently. - PHPStan 2.1.39 types the keys of get_object_vars() as array-key. Co-authored-by: Pascal Birchler <pascal.birchler@gmail.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BdixSnMLgw1cC5m1ZSP5Kd
Co-authored-by: Pascal Birchler <pascal.birchler@gmail.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BdixSnMLgw1cC5m1ZSP5Kd
Greptile SummaryThis PR adds a PHPStan 2.x dynamic return-type extension for
Confidence Score: 5/5The PR appears safe to merge, with the prior named-argument issue fully addressed and no new actionable defects identified. Named calls are now normalized before positional indexing, and tests cover both named-argument orders. The additional namespace-resolution and version-gating changes use safe fallbacks and match established repository patterns.
|
| Filename | Overview |
|---|---|
| src/WpParseArgsDynamicFunctionReturnTypeExtension.php | Adds conservative wp_parse_args() return-type inference, including normalized named arguments and fully qualified synthetic built-in calls. |
| extension.neon | Registers the new dynamic function return-type extension with PHPStan. |
| tests/DynamicReturnTypeExtensionTest.php | Loads the new fixtures with appropriate PHP and PHPStan version gates. |
| tests/data/wp-parse-args.php | Covers array shapes, precedence, empty and invalid defaults, string fallback, class scope, and namespace shadowing. |
| tests/data/wp-parse-args-named-args.php | Verifies named arguments are normalized correctly regardless of their source order. |
| tests/data/wp-parse-args-phpstan-2.1.39.php | Covers inference whose expected representation depends on PHPStan 2.1.39 or later. |
| .travis.yml | Prevents PHP 7.4 syntax checks from parsing the PHP 8-only named-argument fixture. |
| composer.json | Updates the development WPCS constraint while retaining the compatibility alias. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[wp_parse_args call] --> B[Normalize arguments]
B --> C{Normalization succeeded<br/>and no unpacking?}
C -- No --> F[Use declared return type]
C -- Yes --> D{args is an array or<br/>safe object conversion?}
D -- No --> F
D -- Yes --> E{defaults supplied as array?}
E -- No --> G[Return parsed args type]
E -- Yes --> H[Infer array_merge of defaults and args]
H --> I{Defaults definitely non-empty?}
I -- Yes --> J[Return merged type]
I -- No --> K[Union merged and original args types]
Reviews (2): Last reviewed commit: "Address review feedback for wp_parse_arg..." | Re-trigger Greptile
There was a problem hiding this comment.
🟡 Changes recommended
The new extension builds synthetic calls using unqualified built-in function names, which can resolve in the caller’s namespace and yield incorrect inferred types.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR ports the wp_parse_args() dynamic return type extension and its test coverage to the PHPStan 2.x (2.x branch) release line, ensuring callers get precise array-shape inference instead of a generic array<mixed> return type.
Changes:
- Add
WpParseArgsDynamicFunctionReturnTypeExtensionto infer merged array-shape return types forwp_parse_args(). - Add new type-inference test fixtures for
wp_parse_args(), including a PHPStan-version-gated fixture for behavior that changed in PHPStan 2.1.x. - Register the new extension in
extension.neonand bump the WPCS dev dependency pin.
File summaries
| File | Description |
|---|---|
| tests/DynamicReturnTypeExtensionTest.php | Adds PHPStan-version-gated inclusion of an additional wp_parse_args() assert fixture and includes the base fixture. |
| tests/data/wp-parse-args.php | Adds core wp_parse_args() type assertion coverage (array-shapes, defaults precedence, ignored defaults, query string/object cases). |
| tests/data/wp-parse-args-phpstan-2.1.39.php | Adds PHPStan-2.1.39-gated assertions for behaviors affected by PHPStan internal type normalization changes. |
| src/WpParseArgsDynamicFunctionReturnTypeExtension.php | Implements the dynamic return type extension for wp_parse_args(). |
| extension.neon | Registers the new dynamic return type extension service. |
| composer.json | Updates the WPCS alias pin from 3.1.0 to 3.4.1 (aliased as 2.3.0). |
Review details
Suppressed comments (1)
src/WpParseArgsDynamicFunctionReturnTypeExtension.php:101
- The synthetic
get_object_vars()call is created with an unqualified name, so it can be resolved against the caller’s namespace instead of the global built-in. Use a fully-qualified name to ensure the correct function is analysed.
return new FuncCall(new Name('get_object_vars'), [new Arg($argsExpr)]);
- Files reviewed: 6/6 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Normalize the arguments of wp_parse_args() through NormalizedArguments, so named arguments in any order are matched up with the right parameter. - Resolve the synthetic array_merge() and get_object_vars() calls with fully qualified names, so a function of the same name in the caller's namespace cannot shadow the built-in ones. - Cover both cases in the tests. The named arguments file is excluded from the PHP 7.4 syntax lint like the existing hook-callback-named-args.php. Co-authored-by: Pascal Birchler <pascal.birchler@gmail.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BdixSnMLgw1cC5m1ZSP5Kd
|
This PR is nice and long. |
This ports #309 to the 2.x branch. I mistakenly opened #309 against
master, which is the 1.x line for PHPStan 1, so the extension never reached the PHPStan 2 release line. Apologies for the mix-up.The extension itself is unchanged. What differs from #309:
tests/data/wp-parse-args-phpstan-2.1.39.phpand only run on PHPStan ^2.1.39, like the existing slashit gate. PHPStan 2.1.1 changed howunions of array shapes are normalized, and PHPStan 2.1.39 changed the keys of
get_object_vars()fromstringtoarray-key.wp_parse_args()#309 is included as a separate commit. It resolves toszepeviktor/phpcs-psr-12-neutron-hybrid-rulesetv1.2.0, which carries the same pin, and the lowest-deps setup matches what already passes onmaster.