1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type;
4:
5: use PHPStan\Php\PhpVersion;
6: use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
7: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
8: use PHPStan\Reflection\ReflectionProvider;
9: use PHPStan\TrinaryLogic;
10: use PHPStan\Turbo\ShadowedByTurboExtension;
11: use PHPStan\Type\Constant\ConstantArrayType;
12: use PHPStan\Type\Constant\ConstantBooleanType;
13: use PHPStan\Type\Constant\ConstantFloatType;
14: use PHPStan\Type\Constant\ConstantIntegerType;
15: use PHPStan\Type\Constant\ConstantStringType;
16: use PHPStan\Type\Traits\FalseyBooleanTypeTrait;
17: use PHPStan\Type\Traits\NonArrayTypeTrait;
18: use PHPStan\Type\Traits\NonCallableTypeTrait;
19: use PHPStan\Type\Traits\NonGenericTypeTrait;
20: use PHPStan\Type\Traits\NonIterableTypeTrait;
21: use PHPStan\Type\Traits\NonObjectTypeTrait;
22: use PHPStan\Type\Traits\NonRemoveableTypeTrait;
23:
24: /** @api */
25: #[InstanceofDeprecated(insteadUse: 'Type::isNull()')]
26: #[ShadowedByTurboExtension(implementation: __DIR__ . '/../../turbo-ext/src/NullType.cpp')]
27: class NullType implements ConstantScalarType
28: {
29:
30: use NonArrayTypeTrait;
31: use NonCallableTypeTrait;
32: use NonIterableTypeTrait;
33: use NonObjectTypeTrait;
34: use FalseyBooleanTypeTrait;
35: use NonGenericTypeTrait;
36: use NonRemoveableTypeTrait;
37:
38: /** @api */
39: public function __construct()
40: {
41: }
42:
43: public function getReferencedClasses(): array
44: {
45: return [];
46: }
47:
48: public function getObjectClassNames(): array
49: {
50: return [];
51: }
52:
53: public function getObjectClassReflections(): array
54: {
55: return [];
56: }
57:
58: public function getConstantStrings(): array
59: {
60: return [];
61: }
62:
63: /**
64: * @return null
65: */
66: public function getValue()
67: {
68: return null;
69: }
70:
71: public function generalize(GeneralizePrecision $precision): Type
72: {
73: return $this;
74: }
75:
76: public function accepts(Type $type, bool $strictTypes): AcceptsResult
77: {
78: if ($type instanceof self) {
79: return AcceptsResult::createYes();
80: }
81:
82: if ($type instanceof CompoundType) {
83: return $type->isAcceptedBy($this, $strictTypes);
84: }
85:
86: return AcceptsResult::createNo();
87: }
88:
89: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult
90: {
91: if ($type instanceof self) {
92: return IsSuperTypeOfResult::createYes();
93: }
94:
95: if ($type instanceof CompoundType) {
96: return $type->isSubTypeOf($this);
97: }
98:
99: return IsSuperTypeOfResult::createNo();
100: }
101:
102: public function equals(Type $type): bool
103: {
104: return $type instanceof self;
105: }
106:
107: public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
108: {
109: if ($otherType instanceof ConstantScalarType) {
110: return TrinaryLogic::createFromBoolean(null < $otherType->getValue());
111: }
112:
113: if ($otherType instanceof CompoundType) {
114: return $otherType->isGreaterThan($this, $phpVersion);
115: }
116:
117: if ($otherType->isObject()->yes()) {
118: return TrinaryLogic::createYes();
119: }
120:
121: return TrinaryLogic::createMaybe();
122: }
123:
124: public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic
125: {
126: if ($otherType instanceof ConstantScalarType) {
127: return TrinaryLogic::createFromBoolean(null <= $otherType->getValue());
128: }
129:
130: if ($otherType instanceof CompoundType) {
131: return $otherType->isGreaterThanOrEqual($this, $phpVersion);
132: }
133:
134: if ($otherType->isObject()->yes()) {
135: return TrinaryLogic::createYes();
136: }
137:
138: return TrinaryLogic::createMaybe();
139: }
140:
141: public function describe(VerbosityLevel $level): string
142: {
143: return 'null';
144: }
145:
146: public function toNumber(): Type
147: {
148: return new ConstantIntegerType(0);
149: }
150:
151: public function toBitwiseNotType(): Type
152: {
153: return new ErrorType();
154: }
155:
156: public function toClassConstantType(ReflectionProvider $reflectionProvider): Type
157: {
158: // Null `::class` reads as `null` (mirrors how `null::class` flows
159: // through the `::class` resolution pipeline alongside object types).
160: return $this;
161: }
162:
163: public function toAbsoluteNumber(): Type
164: {
165: return $this->toNumber()->toAbsoluteNumber();
166: }
167:
168: public function toString(): Type
169: {
170: return new ConstantStringType('');
171: }
172:
173: public function toInteger(): Type
174: {
175: return $this->toNumber();
176: }
177:
178: public function toFloat(): Type
179: {
180: return $this->toNumber()->toFloat();
181: }
182:
183: public function toArray(): Type
184: {
185: return new ConstantArrayType([], []);
186: }
187:
188: public function toArrayKey(): Type
189: {
190: return new ConstantStringType('');
191: }
192:
193: public function toCoercedArgumentType(bool $strictTypes): Type
194: {
195: return $this;
196: }
197:
198: public function isOffsetAccessible(): TrinaryLogic
199: {
200: return TrinaryLogic::createYes();
201: }
202:
203: public function isOffsetAccessLegal(): TrinaryLogic
204: {
205: return TrinaryLogic::createYes();
206: }
207:
208: public function hasOffsetValueType(Type $offsetType): TrinaryLogic
209: {
210: return TrinaryLogic::createNo();
211: }
212:
213: public function getOffsetValueType(Type $offsetType): Type
214: {
215: return new ErrorType();
216: }
217:
218: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
219: {
220: $array = new ConstantArrayType([], []);
221: return $array->setOffsetValueType($offsetType, $valueType, $unionValues);
222: }
223:
224: public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type
225: {
226: return $this;
227: }
228:
229: public function unsetOffset(Type $offsetType): Type
230: {
231: return $this;
232: }
233:
234: public function traverse(callable $cb): Type
235: {
236: return $this;
237: }
238:
239: public function traverseSimultaneously(Type $right, callable $cb): Type
240: {
241: return $this;
242: }
243:
244: public function isNull(): TrinaryLogic
245: {
246: return TrinaryLogic::createYes();
247: }
248:
249: public function isConstantValue(): TrinaryLogic
250: {
251: return TrinaryLogic::createYes();
252: }
253:
254: public function isConstantScalarValue(): TrinaryLogic
255: {
256: return TrinaryLogic::createYes();
257: }
258:
259: public function getConstantScalarTypes(): array
260: {
261: return [$this];
262: }
263:
264: public function getConstantScalarValues(): array
265: {
266: return [$this->getValue()];
267: }
268:
269: public function isTrue(): TrinaryLogic
270: {
271: return TrinaryLogic::createNo();
272: }
273:
274: public function isFalse(): TrinaryLogic
275: {
276: return TrinaryLogic::createNo();
277: }
278:
279: public function isBoolean(): TrinaryLogic
280: {
281: return TrinaryLogic::createNo();
282: }
283:
284: public function isFloat(): TrinaryLogic
285: {
286: return TrinaryLogic::createNo();
287: }
288:
289: public function isInteger(): TrinaryLogic
290: {
291: return TrinaryLogic::createNo();
292: }
293:
294: public function isString(): TrinaryLogic
295: {
296: return TrinaryLogic::createNo();
297: }
298:
299: public function isNumericString(): TrinaryLogic
300: {
301: return TrinaryLogic::createNo();
302: }
303:
304: public function isDecimalIntegerString(): TrinaryLogic
305: {
306: return TrinaryLogic::createNo();
307: }
308:
309: public function isNonEmptyString(): TrinaryLogic
310: {
311: return TrinaryLogic::createNo();
312: }
313:
314: public function isNonFalsyString(): TrinaryLogic
315: {
316: return TrinaryLogic::createNo();
317: }
318:
319: public function isLiteralString(): TrinaryLogic
320: {
321: return TrinaryLogic::createNo();
322: }
323:
324: public function isLowercaseString(): TrinaryLogic
325: {
326: return TrinaryLogic::createNo();
327: }
328:
329: public function isUppercaseString(): TrinaryLogic
330: {
331: return TrinaryLogic::createNo();
332: }
333:
334: public function isClassString(): TrinaryLogic
335: {
336: return TrinaryLogic::createNo();
337: }
338:
339: public function getClassStringObjectType(): Type
340: {
341: return new ErrorType();
342: }
343:
344: public function getObjectTypeOrClassStringObjectType(): Type
345: {
346: return new ErrorType();
347: }
348:
349: public function isVoid(): TrinaryLogic
350: {
351: return TrinaryLogic::createNo();
352: }
353:
354: public function isScalar(): TrinaryLogic
355: {
356: return TrinaryLogic::createNo();
357: }
358:
359: public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
360: {
361: if ($type instanceof ConstantScalarType) {
362: return LooseComparisonHelper::compareConstantScalars($this, $type, $phpVersion);
363: }
364:
365: if ($type->isConstantArray()->yes() && $type->isIterableAtLeastOnce()->no()) {
366: // @phpstan-ignore equal.alwaysTrue, equal.notAllowed
367: return new ConstantBooleanType($this->getValue() == []); // phpcs:ignore
368: }
369:
370: if ($type instanceof CompoundType) {
371: return $type->looseCompare($this, $phpVersion);
372: }
373:
374: return new BooleanType();
375: }
376:
377: public function getSmallerType(PhpVersion $phpVersion): Type
378: {
379: return new NeverType();
380: }
381:
382: public function getSmallerOrEqualType(PhpVersion $phpVersion): Type
383: {
384: // All falsey types except '0'
385: return new UnionType([
386: new NullType(),
387: new ConstantBooleanType(false),
388: new ConstantIntegerType(0),
389: new ConstantFloatType(0.0),
390: new ConstantStringType(''),
391: new ConstantArrayType([], []),
392: ]);
393: }
394:
395: public function getGreaterType(PhpVersion $phpVersion): Type
396: {
397: // All truthy types, but also '0'
398: return new MixedType(subtractedType: new UnionType([
399: new NullType(),
400: new ConstantBooleanType(false),
401: new ConstantIntegerType(0),
402: new ConstantFloatType(0.0),
403: new ConstantStringType(''),
404: new ConstantArrayType([], []),
405: ]));
406: }
407:
408: public function getGreaterOrEqualType(PhpVersion $phpVersion): Type
409: {
410: return new MixedType();
411: }
412:
413: public function getFiniteTypes(): array
414: {
415: return [$this];
416: }
417:
418: public function exponentiate(Type $exponent): Type
419: {
420: return new UnionType(
421: [
422: new ConstantIntegerType(0),
423: new ConstantIntegerType(1),
424: ],
425: );
426: }
427:
428: public function toPhpDocNode(): TypeNode
429: {
430: return new IdentifierTypeNode('null');
431: }
432:
433: public function hasTemplateOrLateResolvableType(): bool
434: {
435: return false;
436: }
437:
438: }
439: