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