Skip to content

Fix phpstan/phpstan#3250: \settype() is not handled properly#5404

Merged
VincentLanglet merged 3 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-x4lf4wf
Apr 6, 2026
Merged

Fix phpstan/phpstan#3250: \settype() is not handled properly#5404
VincentLanglet merged 3 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-x4lf4wf

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

When settype() is called with a non-constant string as the type argument (e.g. a parameter string $castTo), PHPStan did not update the variable's type at all, leading to false positives about impossible return types.

Changes

  • Modified src/Type/Php/SetTypeFunctionTypeSpecifyingExtension.php to handle non-constant type strings by setting the variable type to the union of all possible settype() outcomes: array|bool|float|int|stdClass|string|null
  • Added regression test tests/PHPStan/Analyser/nsrt/bug-3250.php covering non-constant, constant, and union-of-constants type arguments

Root cause

The SetTypeFunctionTypeSpecifyingExtension returned an empty SpecifiedTypes when the second argument had no constant string values, which meant the variable's type was left unchanged after the settype() call. The fix returns a union of all possible result types when the cast target is unknown.

Test

The NSRT test verifies:

  1. Non-constant string type argument produces the full union type
  2. Constant 'int' produces int
  3. Union of 'int'|'float' produces float|int

Fixes phpstan/phpstan#3250

- When settype()'s second argument is a non-constant string, broaden the variable type to all possible settype outcomes (bool|int|float|string|array|object|null)
- Previously, non-constant type strings caused the extension to return empty SpecifiedTypes, leaving the variable type unchanged
- New regression test in tests/PHPStan/Analyser/nsrt/bug-3250.php
$constantStrings = $castType->getConstantStrings();
if (count($constantStrings) < 1) {
return new SpecifiedTypes();
return $this->typeSpecifier->create(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning here, just write

$constantStrings = [...];

with all the valid values and let the foreach do the job.

Also, in the foreach

case 'object':
					$types[] = new ObjectType(stdClass::class);

is not correct as

$a = 1; settype($a, 'object');

gives stdClass but

$a = new \DateTime; settype($a, 'object');

gives a DateTime.

So fix the object case.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. The changes address both review comments:

  1. Reuse foreach for non-constant types: Instead of returning a hardcoded union type, the non-constant fallback now populates $constantStrings with all valid settype values (bool, int, float, string, array, object, null) and lets the existing foreach do the work. This avoids duplicating the type mapping logic.

  2. Fix the object case: The object case now correctly handles three scenarios:

    • Value is definitely an object → keeps original type (e.g. DateTime stays DateTime)
    • Value is definitely not an object → produces stdClass
    • Value might be an object → union of the object part of the type with stdClass (e.g. DateTime|stringDateTime|stdClass)

…ix object case

Instead of returning a hardcoded union for non-constant type strings,
populate $constantStrings with all valid values and let the existing
foreach handle them. This avoids duplicating the type mapping logic.

Fix the 'object' case to preserve the original type when the value is
already an object (e.g. settype($dateTime, 'object') keeps DateTime),
instead of always returning stdClass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
break;
case 'object':
$types[] = new ObjectType(stdClass::class);
if ($valueType->isObject()->yes()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a constant for $valueType->isObject() to avoid computing it two times.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The background make phpstan task completed successfully (already saw the result earlier — no errors). Everything is done and pushed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@VincentLanglet VincentLanglet requested a review from staabm April 6, 2026 09:42
@VincentLanglet VincentLanglet merged commit 06ea1e1 into phpstan:2.1.x Apr 6, 2026
655 of 657 checks passed
@VincentLanglet VincentLanglet deleted the create-pull-request/patch-x4lf4wf branch April 6, 2026 10:03
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.

3 participants