Skip to content

Commit 590eb03

Browse files
committed
Understand get_class compared with static::class
1 parent 106526d commit 590eb03

File tree

5 files changed

+67
-32
lines changed

5 files changed

+67
-32
lines changed

phpstan-baseline.neon

-5
Original file line numberDiff line numberDiff line change
@@ -1512,11 +1512,6 @@ parameters:
15121512
count: 1
15131513
path: src/Type/StaticType.php
15141514

1515-
-
1516-
message: "#^PHPDoc tag @var assumes the expression with type PHPStan\\\\Type\\\\Type is always PHPStan\\\\Type\\\\StaticType but it's error\\-prone and dangerous\\.$#"
1517-
count: 1
1518-
path: src/Type/StaticType.php
1519-
15201515
-
15211516
message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#"
15221517
count: 1

src/Analyser/TypeSpecifier.php

+37-25
Original file line numberDiff line numberDiff line change
@@ -181,27 +181,61 @@ public function specifyTypesInCondition(
181181
return $this->create($exprNode, new ObjectWithoutClassType(), $context, false, $scope, $rootExpr);
182182
}
183183
} elseif ($expr instanceof Node\Expr\BinaryOp\Identical) {
184+
$leftExpr = $expr->left;
185+
$rightExpr = $expr->right;
186+
if ($rightExpr instanceof FuncCall && !$leftExpr instanceof FuncCall) {
187+
[$leftExpr, $rightExpr] = [$rightExpr, $leftExpr];
188+
}
189+
$unwrappedLeftExpr = $leftExpr;
190+
if ($leftExpr instanceof AlwaysRememberedExpr) {
191+
$unwrappedLeftExpr = $leftExpr->getExpr();
192+
}
193+
$rightType = $scope->getType($rightExpr);
194+
if (
195+
$context->true()
196+
&& $unwrappedLeftExpr instanceof FuncCall
197+
&& $unwrappedLeftExpr->name instanceof Name
198+
&& strtolower($unwrappedLeftExpr->name->toString()) === 'get_class'
199+
&& isset($unwrappedLeftExpr->getArgs()[0])
200+
) {
201+
if ($rightType->getClassStringObjectType()->isObject()->yes()) {
202+
return $this->create(
203+
$unwrappedLeftExpr->getArgs()[0]->value,
204+
$rightType->getClassStringObjectType(),
205+
$context,
206+
false,
207+
$scope,
208+
$rootExpr,
209+
)->unionWith($this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr));
210+
}
211+
}
212+
184213
$expressions = $this->findTypeExpressionsFromBinaryOperation($scope, $expr);
185214
if ($expressions !== null) {
186215
$exprNode = $expressions[0];
187216
$constantType = $expressions[1];
188217

218+
if ($constantType instanceof ConstantStringType) {
219+
$specifiedType = $this->specifyTypesForConstantStringBinaryExpression($exprNode, $constantType, $context, $scope, $rootExpr);
220+
if ($specifiedType !== null) {
221+
return $specifiedType;
222+
}
223+
}
224+
189225
$specifiedType = $this->specifyTypesForConstantBinaryExpression($exprNode, $constantType, $context, $scope, $rootExpr);
190226
if ($specifiedType !== null) {
191227
return $specifiedType;
192228
}
193229
}
194230

195-
$rightExpr = $expr->right;
196231
if ($rightExpr instanceof AlwaysRememberedExpr) {
197232
$rightExpr = $rightExpr->getExpr();
198233
}
199234

200-
$leftExpr = $expr->left;
201235
if ($leftExpr instanceof AlwaysRememberedExpr) {
202236
$leftExpr = $leftExpr->getExpr();
203237
}
204-
$rightType = $scope->getType($rightExpr);
238+
205239
if (
206240
$leftExpr instanceof ClassConstFetch &&
207241
$leftExpr->class instanceof Expr &&
@@ -1020,10 +1054,6 @@ private function specifyTypesForConstantBinaryExpression(
10201054

10211055
}
10221056

1023-
if ($constantType instanceof ConstantStringType) {
1024-
return $this->specifyTypesForConstantStringBinaryExpression($exprNode, $constantType, $context, $scope, $rootExpr);
1025-
}
1026-
10271057
return null;
10281058
}
10291059

@@ -1110,24 +1140,6 @@ private function specifyTypesForConstantStringBinaryExpression(
11101140
}
11111141
}
11121142

1113-
if (
1114-
$context->true()
1115-
&& $unwrappedExprNode instanceof FuncCall
1116-
&& $unwrappedExprNode->name instanceof Name
1117-
&& strtolower($unwrappedExprNode->name->toString()) === 'get_class'
1118-
&& isset($unwrappedExprNode->getArgs()[0])
1119-
) {
1120-
return $this->specifyTypesInCondition(
1121-
$scope,
1122-
new Instanceof_(
1123-
$unwrappedExprNode->getArgs()[0]->value,
1124-
new Name($constantType->getValue()),
1125-
),
1126-
$context,
1127-
$rootExpr,
1128-
)->unionWith($this->create($exprNode, $constantType, $context, false, $scope, $rootExpr));
1129-
}
1130-
11311143
if (
11321144
$context->true()
11331145
&& $exprNode instanceof FuncCall

src/Type/StaticType.php

-2
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,6 @@ public function equals(Type $type): bool
184184
return false;
185185
}
186186

187-
/** @var StaticType $type */
188-
$type = $type;
189187
return $this->getStaticObjectType()->equals($type->getStaticObjectType());
190188
}
191189

tests/PHPStan/Analyser/NodeScopeResolverTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ public function dataFileAsserts(): iterable
195195

196196
yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-sprintf.php');
197197

198+
yield from $this->gatherAssertTypes(__DIR__ . '/data/get-class-static-class.php');
199+
198200
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2816.php');
199201

200202
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2816-2.php');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace GetClassStaticClass;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
10+
public function doFoo(object $o): void
11+
{
12+
if (get_class($o) !== static::class) {
13+
return;
14+
}
15+
16+
assertType('static(GetClassStaticClass\Foo)', $o);
17+
}
18+
19+
public function doFoo2(object $o): void
20+
{
21+
if (static::class !== get_class($o)) {
22+
return;
23+
}
24+
25+
assertType('static(GetClassStaticClass\Foo)', $o);
26+
}
27+
28+
}

0 commit comments

Comments
 (0)