Skip to content

Commit 85b4f24

Browse files
phpstan-botVincentLangletclaude
authored
Fix phpstan/phpstan#7088: Accessing SimpleXMLElement nodes using braces gives mixed type (#5406)
Co-authored-by: VincentLanglet <9052536+VincentLanglet@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 67e37ac commit 85b4f24

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

src/Analyser/ExprHandler/PropertyFetchHandler.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@
3333
final class PropertyFetchHandler implements ExprHandler
3434
{
3535

36+
/**
37+
* Representative property name used when resolving dynamic property access ($obj->{$expr}).
38+
* The actual name doesn't matter — it just needs to be non-empty so that
39+
* PropertiesClassReflectionExtensions (e.g. SimpleXMLElement) that accept
40+
* any property name can return the correct type.
41+
*/
42+
private const DYNAMIC_PROPERTY_NAME = '__phpstan_dynamic_property';
43+
3644
public function __construct(
3745
private PhpVersion $phpVersion,
3846
private PropertyReflectionFinder $propertyReflectionFinder,
@@ -130,6 +138,14 @@ public function resolveType(MutatingScope $scope, Expr $expr): Type
130138
);
131139
}
132140

141+
if ($nameType->isString()->yes()) {
142+
$fetchedOnType = $scope->getType($expr->var);
143+
$returnType = $this->propertyFetchType($scope, $fetchedOnType, self::DYNAMIC_PROPERTY_NAME, $expr);
144+
if ($returnType !== null) {
145+
return NullsafeShortCircuitingHelper::getType($scope, $expr->var, $returnType);
146+
}
147+
}
148+
133149
return new MixedType();
134150
}
135151

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug7088;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
public function sayHello(\SimpleXMLElement $prop, string $x): void
10+
{
11+
assertType('(SimpleXMLElement|null)', $prop->foo);
12+
assertType('(SimpleXMLElement|null)', $prop->{'foo-bar'});
13+
assertType('(SimpleXMLElement|null)', $prop->{$x});
14+
}
15+
}

0 commit comments

Comments
 (0)