Skip to content

Fix #10396: preg_replace_callback doesn't account for flags in callback signature#4971

Open
phpstan-bot wants to merge 1 commit into2.1.xfrom
create-pull-request/patch-svpdd33
Open

Fix #10396: preg_replace_callback doesn't account for flags in callback signature#4971
phpstan-bot wants to merge 1 commit into2.1.xfrom
create-pull-request/patch-svpdd33

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

Fixes phpstan/phpstan#10396

When preg_replace_callback or preg_replace_callback_array is called with PREG_OFFSET_CAPTURE and/or PREG_UNMATCHED_AS_NULL flags, PHPStan now accounts for these flags when determining the expected callback parameter type.

Previously, PHPStan always expected callable(array<string>): string regardless of flags, causing false positives when users correctly typed their callbacks for flag-aware match arrays (e.g., array<int|string, array{string|null, int}> for PREG_OFFSET_CAPTURE | PREG_UNMATCHED_AS_NULL).

Additionally, preg_replace_callback_array callbacks now get proper type inference for the $matches parameter when flags are used (previously always inferred as mixed).

Changes

  • New PregReplaceCallbackArgVisitor: AST visitor that sets a pregReplaceCallbackFlags attribute on callback arguments (for preg_replace_callback) and on closure/arrow function nodes inside the array argument (for preg_replace_callback_array), following the same pattern as ArrayMapArgVisitor.

  • ParametersAcceptorSelector: When the flags attribute is present, overrides the callback parameter type to account for PREG_OFFSET_CAPTURE (match values become array{string, int<-1, max>}) and PREG_UNMATCHED_AS_NULL (match values include null). This fixes call-site validation.

  • NodeScopeResolver::createCallableParameters(): When a closure/arrow function has the flags attribute, computes flag-aware callable parameters for scope inference inside the closure body. This fixes type inference for $matches inside preg_replace_callback_array callbacks.

  • MutatingScope::getClosureType(): Reads the flags attribute to construct the correct external closure type.

Flag behavior

Flags Match value type
None string
PREG_UNMATCHED_AS_NULL string|null
PREG_OFFSET_CAPTURE array{string, int<-1, max>}
Both array{string|null, int<-1, max>}

…reg_replace_callback and preg_replace_callback_array callback signatures

Fixes phpstan/phpstan#10396
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant