1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Accessory;
4:
5: use PHPStan\Reflection\ClassMemberAccessAnswerer;
6: use PHPStan\Reflection\TrivialParametersAcceptor;
7: use PHPStan\TrinaryLogic;
8: use PHPStan\Type\CompoundType;
9: use PHPStan\Type\IntersectionType;
10: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
11: use PHPStan\Type\Traits\NonGenericTypeTrait;
12: use PHPStan\Type\Traits\NonRemoveableTypeTrait;
13: use PHPStan\Type\Traits\ObjectTypeTrait;
14: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
15: use PHPStan\Type\Type;
16: use PHPStan\Type\UnionType;
17: use PHPStan\Type\VerbosityLevel;
18: use function sprintf;
19:
20: class HasPropertyType implements AccessoryType, CompoundType
21: {
22:
23: use ObjectTypeTrait;
24: use NonGenericTypeTrait;
25: use UndecidedComparisonCompoundTypeTrait;
26: use NonRemoveableTypeTrait;
27: use NonGeneralizableTypeTrait;
28:
29: /** @api */
30: public function __construct(private string $propertyName)
31: {
32: }
33:
34: /**
35: * @return string[]
36: */
37: public function getReferencedClasses(): array
38: {
39: return [];
40: }
41:
42: public function getPropertyName(): string
43: {
44: return $this->propertyName;
45: }
46:
47: public function accepts(Type $type, bool $strictTypes): TrinaryLogic
48: {
49: return TrinaryLogic::createFromBoolean($this->equals($type));
50: }
51:
52: public function isSuperTypeOf(Type $type): TrinaryLogic
53: {
54: return $type->hasProperty($this->propertyName);
55: }
56:
57: public function isSubTypeOf(Type $otherType): TrinaryLogic
58: {
59: if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
60: return $otherType->isSuperTypeOf($this);
61: }
62:
63: if ($otherType instanceof self) {
64: $limit = TrinaryLogic::createYes();
65: } else {
66: $limit = TrinaryLogic::createMaybe();
67: }
68:
69: return $limit->and($otherType->hasProperty($this->propertyName));
70: }
71:
72: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic
73: {
74: return $this->isSubTypeOf($acceptingType);
75: }
76:
77: public function equals(Type $type): bool
78: {
79: return $type instanceof self
80: && $this->propertyName === $type->propertyName;
81: }
82:
83: public function describe(VerbosityLevel $level): string
84: {
85: return sprintf('hasProperty(%s)', $this->propertyName);
86: }
87:
88: public function hasProperty(string $propertyName): TrinaryLogic
89: {
90: if ($this->propertyName === $propertyName) {
91: return TrinaryLogic::createYes();
92: }
93:
94: return TrinaryLogic::createMaybe();
95: }
96:
97: public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array
98: {
99: return [new TrivialParametersAcceptor()];
100: }
101:
102: public function traverse(callable $cb): Type
103: {
104: return $this;
105: }
106:
107: public static function __set_state(array $properties): Type
108: {
109: return new self($properties['propertyName']);
110: }
111:
112: }
113: