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