Skip to content

Commit 0d10427

Browse files
committed
ObjectType: fix isEnum
1 parent 7b2fd6c commit 0d10427

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

src/Type/ObjectType.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use ArrayAccess;
66
use ArrayObject;
7+
use BackedEnum;
78
use Closure;
89
use Countable;
910
use Iterator;
@@ -44,7 +45,10 @@
4445
use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
4546
use PHPStan\Type\Traits\NonGenericTypeTrait;
4647
use PHPStan\Type\Traits\UndecidedComparisonTypeTrait;
48+
use Stringable;
49+
use Throwable;
4750
use Traversable;
51+
use UnitEnum;
4852
use function array_key_exists;
4953
use function array_map;
5054
use function array_values;
@@ -730,7 +734,23 @@ public function isEnum(): TrinaryLogic
730734
return TrinaryLogic::createMaybe();
731735
}
732736

733-
return TrinaryLogic::createFromBoolean($classReflection->isEnum());
737+
if (
738+
$classReflection->isEnum()
739+
|| $classReflection->is(UnitEnum::class)
740+
|| $classReflection->is(BackedEnum::class)
741+
) {
742+
return TrinaryLogic::createYes();
743+
}
744+
745+
if (
746+
$classReflection->isInterface()
747+
&& !$classReflection->is(Stringable::class) // enums cannot have __toString
748+
&& !$classReflection->is(Throwable::class) // enums cannot extend Exception/Error
749+
) {
750+
return TrinaryLogic::createMaybe();
751+
}
752+
753+
return TrinaryLogic::createNo();
734754
}
735755

736756
public function canAccessProperties(): TrinaryLogic

tests/PHPStan/Type/ObjectTypeTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,35 @@ public function testIsIterable(ObjectType $type, TrinaryLogic $expectedResult):
7070
);
7171
}
7272

73+
/**
74+
* @return array<array{0: ObjectType, 1: TrinaryLogic}>
75+
*/
76+
public function dataIsEnum(): array
77+
{
78+
return [
79+
[new ObjectType('UnitEnum'), TrinaryLogic::createYes()],
80+
[new ObjectType('BackedEnum'), TrinaryLogic::createYes()],
81+
[new ObjectType('Unknown'), TrinaryLogic::createMaybe()],
82+
[new ObjectType('Countable'), TrinaryLogic::createMaybe()],
83+
[new ObjectType('Stringable'), TrinaryLogic::createNo()],
84+
[new ObjectType('Throwable'), TrinaryLogic::createNo()],
85+
[new ObjectType('DateTime'), TrinaryLogic::createNo()],
86+
];
87+
}
88+
89+
/**
90+
* @dataProvider dataIsEnum
91+
*/
92+
public function testIsEnum(ObjectType $type, TrinaryLogic $expectedResult): void
93+
{
94+
$actualResult = $type->isEnum();
95+
$this->assertSame(
96+
$expectedResult->describe(),
97+
$actualResult->describe(),
98+
sprintf('%s -> isEnum()', $type->describe(VerbosityLevel::precise())),
99+
);
100+
}
101+
73102
public function dataIsCallable(): array
74103
{
75104
return [

0 commit comments

Comments
 (0)