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