Skip to content

Commit 630430f

Browse files
authored
Fix: Return of parent::__set_state() method is only object
1 parent 7c68a12 commit 630430f

File tree

3 files changed

+55
-21
lines changed

3 files changed

+55
-21
lines changed

src/Reflection/Php/PhpMethodReflection.php

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -314,30 +314,33 @@ private function getReturnType(): Type
314314
{
315315
if ($this->returnType === null) {
316316
$name = strtolower($this->getName());
317-
if (
318-
$name === '__construct'
319-
|| $name === '__destruct'
320-
|| $name === '__unset'
321-
|| $name === '__wakeup'
322-
|| $name === '__clone'
323-
) {
324-
return $this->returnType = TypehintHelper::decideType(new VoidType(), $this->phpDocReturnType);
325-
}
326-
if ($name === '__tostring') {
327-
return $this->returnType = TypehintHelper::decideType(new StringType(), $this->phpDocReturnType);
328-
}
329-
if ($name === '__isset') {
330-
return $this->returnType = TypehintHelper::decideType(new BooleanType(), $this->phpDocReturnType);
331-
}
332-
if ($name === '__sleep') {
333-
return $this->returnType = TypehintHelper::decideType(new ArrayType(new IntegerType(), new StringType()), $this->phpDocReturnType);
334-
}
335-
if ($name === '__set_state') {
336-
return $this->returnType = TypehintHelper::decideType(new ObjectWithoutClassType(), $this->phpDocReturnType);
317+
$returnType = $this->reflection->getReturnType();
318+
if ($returnType === null) {
319+
if (
320+
$name === '__construct'
321+
|| $name === '__destruct'
322+
|| $name === '__unset'
323+
|| $name === '__wakeup'
324+
|| $name === '__clone'
325+
) {
326+
return $this->returnType = TypehintHelper::decideType(new VoidType(), $this->phpDocReturnType);
327+
}
328+
if ($name === '__tostring') {
329+
return $this->returnType = TypehintHelper::decideType(new StringType(), $this->phpDocReturnType);
330+
}
331+
if ($name === '__isset') {
332+
return $this->returnType = TypehintHelper::decideType(new BooleanType(), $this->phpDocReturnType);
333+
}
334+
if ($name === '__sleep') {
335+
return $this->returnType = TypehintHelper::decideType(new ArrayType(new IntegerType(), new StringType()), $this->phpDocReturnType);
336+
}
337+
if ($name === '__set_state') {
338+
return $this->returnType = TypehintHelper::decideType(new ObjectWithoutClassType(), $this->phpDocReturnType);
339+
}
337340
}
338341

339342
$this->returnType = TypehintHelper::decideTypeFromReflection(
340-
$this->reflection->getReturnType(),
343+
$returnType,
341344
$this->phpDocReturnType,
342345
$this->declaringClass->getName(),
343346
);

tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,4 +815,9 @@ public function testBug8146bErrors(): void
815815
$this->analyse([__DIR__ . '/data/bug-8146b-errors.php'], []); // there could be a valid error
816816
}
817817

818+
public function testBug8573(): void
819+
{
820+
$this->analyse([__DIR__ . '/data/bug-8573.php'], []);
821+
}
822+
818823
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types = 1);
2+
3+
class A
4+
{
5+
final public function __construct() { }
6+
7+
/**
8+
* @param array<string, mixed> $data
9+
*/
10+
public static function __set_state(array $data): static
11+
{
12+
$obj = new static();
13+
14+
return $obj;
15+
}
16+
}
17+
18+
class B extends A
19+
{
20+
public static function __set_state(array $data): static
21+
{
22+
$obj = parent::__set_state($data);
23+
24+
return $obj;
25+
}
26+
}

0 commit comments

Comments
 (0)