1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Accessory;
4:
5: use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
6: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
7: use PHPStan\Reflection\ClassMemberAccessAnswerer;
8: use PHPStan\Reflection\TrivialParametersAcceptor;
9: use PHPStan\TrinaryLogic;
10: use PHPStan\Type\AcceptsResult;
11: use PHPStan\Type\CompoundType;
12: use PHPStan\Type\ErrorType;
13: use PHPStan\Type\IntersectionType;
14: use PHPStan\Type\IsSuperTypeOfResult;
15: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
16: use PHPStan\Type\Traits\NonGenericTypeTrait;
17: use PHPStan\Type\Traits\NonRemoveableTypeTrait;
18: use PHPStan\Type\Traits\ObjectTypeTrait;
19: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
20: use PHPStan\Type\Type;
21: use PHPStan\Type\UnionType;
22: use PHPStan\Type\VerbosityLevel;
23: use function sprintf;
24:
25: class HasPropertyType implements AccessoryType, CompoundType
26: {
27:
28: use ObjectTypeTrait;
29: use NonGenericTypeTrait;
30: use UndecidedComparisonCompoundTypeTrait;
31: use NonRemoveableTypeTrait;
32: use NonGeneralizableTypeTrait;
33:
34: /** @api */
35: public function __construct(private string $propertyName)
36: {
37: }
38:
39: public function getReferencedClasses(): array
40: {
41: return [];
42: }
43:
44: public function getObjectClassNames(): array
45: {
46: return [];
47: }
48:
49: public function getObjectClassReflections(): array
50: {
51: return [];
52: }
53:
54: public function getConstantStrings(): array
55: {
56: return [];
57: }
58:
59: public function getPropertyName(): string
60: {
61: return $this->propertyName;
62: }
63:
64: public function accepts(Type $type, bool $strictTypes): AcceptsResult
65: {
66: if ($type instanceof CompoundType) {
67: return $type->isAcceptedBy($this, $strictTypes);
68: }
69:
70: return AcceptsResult::createFromBoolean($this->equals($type));
71: }
72:
73: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult
74: {
75: return new IsSuperTypeOfResult(
76: $type->hasInstanceProperty($this->propertyName)->or($type->hasStaticProperty($this->propertyName)),
77: [],
78: );
79: }
80:
81: public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
82: {
83: if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
84: return $otherType->isSuperTypeOf($this);
85: }
86:
87: if ($otherType instanceof self) {
88: $limit = IsSuperTypeOfResult::createYes();
89: } else {
90: $limit = IsSuperTypeOfResult::createMaybe();
91: }
92:
93: return $limit->and(new IsSuperTypeOfResult(
94: $otherType->hasInstanceProperty($this->propertyName)->or($otherType->hasStaticProperty($this->propertyName)),
95: [],
96: ));
97: }
98:
99: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult
100: {
101: return $this->isSubTypeOf($acceptingType)->toAcceptsResult();
102: }
103:
104: public function equals(Type $type): bool
105: {
106: return $type instanceof self
107: && $this->propertyName === $type->propertyName;
108: }
109:
110: public function describe(VerbosityLevel $level): string
111: {
112: return sprintf('hasProperty(%s)', $this->propertyName);
113: }
114:
115: public function hasProperty(string $propertyName): TrinaryLogic
116: {
117: if ($this->propertyName === $propertyName) {
118: return TrinaryLogic::createYes();
119: }
120:
121: return TrinaryLogic::createMaybe();
122: }
123:
124: public function hasInstanceProperty(string $propertyName): TrinaryLogic
125: {
126: if ($this->propertyName === $propertyName) {
127: return TrinaryLogic::createYes();
128: }
129:
130: return TrinaryLogic::createMaybe();
131: }
132:
133: public function hasStaticProperty(string $propertyName): TrinaryLogic
134: {
135: if ($this->propertyName === $propertyName) {
136: return TrinaryLogic::createYes();
137: }
138:
139: return TrinaryLogic::createMaybe();
140: }
141:
142: public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array
143: {
144: return [new TrivialParametersAcceptor()];
145: }
146:
147: public function getEnumCases(): array
148: {
149: return [];
150: }
151:
152: public function traverse(callable $cb): Type
153: {
154: return $this;
155: }
156:
157: public function traverseSimultaneously(Type $right, callable $cb): Type
158: {
159: return $this;
160: }
161:
162: public function exponentiate(Type $exponent): Type
163: {
164: return new ErrorType();
165: }
166:
167: public function getFiniteTypes(): array
168: {
169: return [];
170: }
171:
172: public function toPhpDocNode(): TypeNode
173: {
174: return new IdentifierTypeNode(''); // no PHPDoc representation
175: }
176:
177: }
178: