1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Accessory;
4:
5: use PHPStan\Php\PhpVersion;
6: use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
7: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
8: use PHPStan\TrinaryLogic;
9: use PHPStan\Turbo\ShadowedByTurboExtension;
10: use PHPStan\Type\AcceptsResult;
11: use PHPStan\Type\BooleanType;
12: use PHPStan\Type\CompoundType;
13: use PHPStan\Type\Enum\EnumCaseObjectType;
14: use PHPStan\Type\ErrorType;
15: use PHPStan\Type\Generic\GenericClassStringType;
16: use PHPStan\Type\InstanceofDeprecated;
17: use PHPStan\Type\IntersectionType;
18: use PHPStan\Type\IsSuperTypeOfResult;
19: use PHPStan\Type\MixedType;
20: use PHPStan\Type\ObjectWithoutClassType;
21: use PHPStan\Type\Traits\MaybeCallableTypeTrait;
22: use PHPStan\Type\Traits\MaybeIterableTypeTrait;
23: use PHPStan\Type\Traits\MaybeObjectTypeTrait;
24: use PHPStan\Type\Traits\MaybeOffsetAccessibleTypeTrait;
25: use PHPStan\Type\Traits\MaybeStringTypeTrait;
26: use PHPStan\Type\Traits\NonArrayTypeTrait;
27: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
28: use PHPStan\Type\Traits\NonGenericTypeTrait;
29: use PHPStan\Type\Traits\NonRemoveableTypeTrait;
30: use PHPStan\Type\Traits\TruthyBooleanTypeTrait;
31: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
32: use PHPStan\Type\Type;
33: use PHPStan\Type\TypeCombinator;
34: use PHPStan\Type\UnionType;
35: use PHPStan\Type\VerbosityLevel;
36: use function sprintf;
37:
38: #[InstanceofDeprecated(insteadUse: 'Type::hasProperty()')]
39: #[ShadowedByTurboExtension(implementation: __DIR__ . '/../../../turbo-ext/src/HasPropertyType.cpp')]
40: class HasPropertyType implements AccessoryType, CompoundType
41: {
42:
43: use MaybeCallableTypeTrait;
44: use MaybeIterableTypeTrait;
45: use MaybeObjectTypeTrait;
46: use MaybeOffsetAccessibleTypeTrait;
47: use MaybeStringTypeTrait;
48: use NonArrayTypeTrait;
49: use TruthyBooleanTypeTrait;
50: use NonGenericTypeTrait;
51: use UndecidedComparisonCompoundTypeTrait;
52: use NonRemoveableTypeTrait;
53: use NonGeneralizableTypeTrait;
54:
55: /** @api */
56: public function __construct(private string $propertyName)
57: {
58: }
59:
60: public function getReferencedClasses(): array
61: {
62: return [];
63: }
64:
65: public function getObjectClassNames(): array
66: {
67: return [];
68: }
69:
70: public function getObjectClassReflections(): array
71: {
72: return [];
73: }
74:
75: public function getClassStringType(): Type
76: {
77: return new GenericClassStringType($this);
78: }
79:
80: public function getPropertyName(): string
81: {
82: return $this->propertyName;
83: }
84:
85: public function accepts(Type $type, bool $strictTypes): AcceptsResult
86: {
87: if ($type instanceof CompoundType) {
88: return $type->isAcceptedBy($this, $strictTypes);
89: }
90:
91: return AcceptsResult::createFromBoolean($this->equals($type));
92: }
93:
94: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult
95: {
96: if ($type instanceof CompoundType) {
97: return $type->isSubTypeOf($this);
98: }
99:
100: return new IsSuperTypeOfResult(
101: $type->hasInstanceProperty($this->propertyName)->or($type->hasStaticProperty($this->propertyName)),
102: [],
103: );
104: }
105:
106: public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
107: {
108: if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
109: return $otherType->isSuperTypeOf($this);
110: }
111:
112: if ($otherType instanceof self) {
113: $limit = TrinaryLogic::createYes();
114: } else {
115: $limit = TrinaryLogic::createMaybe();
116: }
117:
118: return new IsSuperTypeOfResult(
119: $limit->and($otherType->hasInstanceProperty($this->propertyName)->or($otherType->hasStaticProperty($this->propertyName))),
120: [],
121: );
122: }
123:
124: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult
125: {
126: return $this->isSubTypeOf($acceptingType)->toAcceptsResult();
127: }
128:
129: public function equals(Type $type): bool
130: {
131: return $type instanceof self
132: && $this->propertyName === $type->propertyName;
133: }
134:
135: public function describe(VerbosityLevel $level): string
136: {
137: return sprintf('hasProperty(%s)', $this->propertyName);
138: }
139:
140: public function hasProperty(string $propertyName): TrinaryLogic
141: {
142: if ($this->propertyName === $propertyName) {
143: return TrinaryLogic::createYes();
144: }
145:
146: return TrinaryLogic::createMaybe();
147: }
148:
149: public function hasInstanceProperty(string $propertyName): TrinaryLogic
150: {
151: if ($this->propertyName === $propertyName) {
152: return TrinaryLogic::createYes();
153: }
154:
155: return TrinaryLogic::createMaybe();
156: }
157:
158: public function hasStaticProperty(string $propertyName): TrinaryLogic
159: {
160: if ($this->propertyName === $propertyName) {
161: return TrinaryLogic::createYes();
162: }
163:
164: return TrinaryLogic::createMaybe();
165: }
166:
167: public function isNull(): TrinaryLogic
168: {
169: return TrinaryLogic::createNo();
170: }
171:
172: public function isConstantValue(): TrinaryLogic
173: {
174: return TrinaryLogic::createNo();
175: }
176:
177: public function isConstantScalarValue(): TrinaryLogic
178: {
179: return TrinaryLogic::createNo();
180: }
181:
182: public function getConstantScalarTypes(): array
183: {
184: return [];
185: }
186:
187: public function getConstantScalarValues(): array
188: {
189: return [];
190: }
191:
192: public function isTrue(): TrinaryLogic
193: {
194: return TrinaryLogic::createNo();
195: }
196:
197: public function isFalse(): TrinaryLogic
198: {
199: return TrinaryLogic::createNo();
200: }
201:
202: public function isBoolean(): TrinaryLogic
203: {
204: return TrinaryLogic::createNo();
205: }
206:
207: public function isFloat(): TrinaryLogic
208: {
209: return TrinaryLogic::createNo();
210: }
211:
212: public function isInteger(): TrinaryLogic
213: {
214: return TrinaryLogic::createNo();
215: }
216:
217: public function getClassStringObjectType(): Type
218: {
219: return $this;
220: }
221:
222: public function getObjectTypeOrClassStringObjectType(): Type
223: {
224: return $this;
225: }
226:
227: public function isVoid(): TrinaryLogic
228: {
229: return TrinaryLogic::createNo();
230: }
231:
232: public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
233: {
234: return new BooleanType();
235: }
236:
237: public function toNumber(): Type
238: {
239: return new ErrorType();
240: }
241:
242: public function toBitwiseNotType(): Type
243: {
244: return new ErrorType();
245: }
246:
247: public function toAbsoluteNumber(): Type
248: {
249: return new ErrorType();
250: }
251:
252: public function toString(): Type
253: {
254: return new ErrorType();
255: }
256:
257: public function toInteger(): Type
258: {
259: return new ErrorType();
260: }
261:
262: public function toFloat(): Type
263: {
264: return new ErrorType();
265: }
266:
267: public function toArray(): Type
268: {
269: return new MixedType();
270: }
271:
272: public function toArrayKey(): Type
273: {
274: return new ErrorType();
275: }
276:
277: public function toCoercedArgumentType(bool $strictTypes): Type
278: {
279: if (!$strictTypes) {
280: return TypeCombinator::union($this, $this->toString());
281: }
282:
283: return $this;
284: }
285:
286: public function getEnumCases(): array
287: {
288: return [];
289: }
290:
291: public function getEnumCaseObject(): ?EnumCaseObjectType
292: {
293: return null;
294: }
295:
296: public function traverse(callable $cb): Type
297: {
298: return $this;
299: }
300:
301: public function traverseSimultaneously(Type $right, callable $cb): Type
302: {
303: return $this;
304: }
305:
306: public function exponentiate(Type $exponent): Type
307: {
308: return new ErrorType();
309: }
310:
311: public function getFiniteTypes(): array
312: {
313: return [];
314: }
315:
316: public function getDefaultBaseType(): Type
317: {
318: return new ObjectWithoutClassType();
319: }
320:
321: public function toPhpDocNode(): TypeNode
322: {
323: return new IdentifierTypeNode(''); // no PHPDoc representation
324: }
325:
326: public function hasTemplateOrLateResolvableType(): bool
327: {
328: return false;
329: }
330:
331: }
332: