Skip to content

Commit b026126

Browse files
committed
Methods in fluent interfaces are considered impure
1 parent a018f1e commit b026126

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

src/Reflection/Annotations/AnnotationMethodReflection.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PHPStan\TrinaryLogic;
1111
use PHPStan\Type\Generic\TemplateTypeMap;
1212
use PHPStan\Type\MixedType;
13+
use PHPStan\Type\ThisType;
1314
use PHPStan\Type\Type;
1415

1516
class AnnotationMethodReflection implements ExtendedMethodReflection
@@ -122,6 +123,10 @@ public function hasSideEffects(): TrinaryLogic
122123
return TrinaryLogic::createYes();
123124
}
124125

126+
if ((new ThisType($this->declaringClass))->isSuperTypeOf($this->returnType)->yes()) {
127+
return TrinaryLogic::createYes();
128+
}
129+
125130
return TrinaryLogic::createMaybe();
126131
}
127132

src/Reflection/Php/PhpMethodReflection.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
use PHPStan\Type\MixedType;
3131
use PHPStan\Type\ObjectWithoutClassType;
3232
use PHPStan\Type\StringType;
33+
use PHPStan\Type\ThisType;
3334
use PHPStan\Type\Type;
3435
use PHPStan\Type\TypehintHelper;
3536
use PHPStan\Type\VoidType;
@@ -430,6 +431,10 @@ public function hasSideEffects(): TrinaryLogic
430431
return TrinaryLogic::createFromBoolean(!$this->isPure);
431432
}
432433

434+
if ((new ThisType($this->declaringClass))->isSuperTypeOf($this->getReturnType())->yes()) {
435+
return TrinaryLogic::createYes();
436+
}
437+
433438
return TrinaryLogic::createMaybe();
434439
}
435440

tests/PHPStan/Analyser/data/impure-method.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
use function PHPStan\Testing\assertType;
66

7+
/**
8+
* @method $this phpDocReturnThis()
9+
*/
710
class Foo
811
{
912

@@ -15,6 +18,14 @@ public function voidMethod(): void
1518
$this->fooProp = rand(0, 1);
1619
}
1720

21+
/**
22+
* @return $this
23+
*/
24+
public function returnsThis()
25+
{
26+
$this->fooProp = rand(0, 1);
27+
}
28+
1829
public function ordinaryMethod(): int
1930
{
2031
return 1;
@@ -51,6 +62,24 @@ public function doFoo(): void
5162
assertType('int', $this->fooProp);
5263
}
5364

65+
public function doFluent(): void
66+
{
67+
$this->fooProp = 1;
68+
assertType('1', $this->fooProp);
69+
70+
$this->returnsThis();
71+
assertType('int', $this->fooProp);
72+
}
73+
74+
public function doFluent2(): void
75+
{
76+
$this->fooProp = 1;
77+
assertType('1', $this->fooProp);
78+
79+
$this->phpDocReturnThis();
80+
assertType('int', $this->fooProp);
81+
}
82+
5483
public function doBar(): void
5584
{
5685
$this->fooProp = 1;

0 commit comments

Comments
 (0)