Thanks to visit codestin.com
Credit goes to apiref.phpstan.org

1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type;
4:
5: use PHPStan\Php\PhpVersion;
6: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
7: use PHPStan\Reflection\Callables\CallableParametersAcceptor;
8: use PHPStan\Reflection\ClassConstantReflection;
9: use PHPStan\Reflection\ClassMemberAccessAnswerer;
10: use PHPStan\Reflection\ClassReflection;
11: use PHPStan\Reflection\ExtendedMethodReflection;
12: use PHPStan\Reflection\ExtendedPropertyReflection;
13: use PHPStan\Reflection\ReflectionProvider;
14: use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection;
15: use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection;
16: use PHPStan\TrinaryLogic;
17: use PHPStan\Type\Constant\ConstantArrayType;
18: use PHPStan\Type\Constant\ConstantStringType;
19: use PHPStan\Type\Enum\EnumCaseObjectType;
20: use PHPStan\Type\Generic\TemplateTypeMap;
21: use PHPStan\Type\Generic\TemplateTypeReference;
22: use PHPStan\Type\Generic\TemplateTypeVariance;
23:
24: /**
25: * Represents a PHPStan type in the type system.
26: *
27: * This is the central interface of PHPStan's type system. Every type that PHPStan
28: * can reason about implements this interface — from simple scalars like StringType
29: * to complex generics like GenericObjectType.
30: *
31: * Each Type knows what it accepts, what is a supertype of it, what properties/methods/constants
32: * it has, what operations it supports, and how to describe itself for error messages.
33: *
34: * Important: Never use `instanceof` to check types. For example, `$type instanceof StringType`
35: * will miss union types, intersection types with accessory types, and other composite forms.
36: * Always use the `is*()` methods or `isSuperTypeOf()` instead:
37: *
38: * // Wrong:
39: * if ($type instanceof StringType) { ... }
40: *
41: * // Correct:
42: * if ($type->isString()->yes()) { ... }
43: *
44: * @api
45: * @api-do-not-implement
46: * @see https://phpstan.org/developing-extensions/type-system
47: */
48: interface Type
49: {
50:
51: /**
52: * Returns all class names referenced anywhere in this type, recursively
53: * (including generic arguments, callable signatures, etc.).
54: *
55: * @see Type::getObjectClassNames() for only direct object type class names
56: *
57: * @return list<non-empty-string>
58: */
59: public function getReferencedClasses(): array;
60:
61: /**
62: * Returns class names of the object types this type directly represents.
63: * Unlike getReferencedClasses(), excludes classes in generic arguments, etc.
64: *
65: * @return list<non-empty-string>
66: */
67: public function getObjectClassNames(): array;
68:
69: /** @return list<ClassReflection> */
70: public function getObjectClassReflections(): array;
71:
72: /**
73: * Return class-string<Foo> for object type Foo.
74: */
75: public function getClassStringType(): Type;
76:
77: /**
78: * Returns the object type for a class-string or literal class name string.
79: * For non-class-string types, returns ErrorType.
80: */
81: public function getClassStringObjectType(): Type;
82:
83: /**
84: * Like getClassStringObjectType(), but also returns object types as-is.
85: * Used for `$classOrObject::method()` where the left side can be either.
86: */
87: public function getObjectTypeOrClassStringObjectType(): Type;
88:
89: public function isObject(): TrinaryLogic;
90:
91: public function isEnum(): TrinaryLogic;
92:
93: /** @return list<ArrayType|ConstantArrayType> */
94: public function getArrays(): array;
95:
96: /**
97: * Only ConstantArrayType instances (array shapes with known keys).
98: *
99: * @return list<ConstantArrayType>
100: */
101: public function getConstantArrays(): array;
102:
103: /** @return list<ConstantStringType> */
104: public function getConstantStrings(): array;
105:
106: /**
107: * Unlike isSuperTypeOf(), accepts() takes into account PHP's implicit type coercion.
108: * With $strictTypes = false, int is accepted by float, and Stringable objects are
109: * accepted by string.
110: */
111: public function accepts(Type $type, bool $strictTypes): AcceptsResult;
112:
113: /**
114: * "Does every value of $type belong to $this type?"
115: *
116: * Preferable to instanceof checks because it correctly handles
117: * union types, intersection types, and all other composite types.
118: */
119: public function isSuperTypeOf(Type $type): IsSuperTypeOfResult;
120:
121: public function equals(Type $type): bool;
122:
123: public function describe(VerbosityLevel $level): string;
124:
125: public function canAccessProperties(): TrinaryLogic;
126:
127: /** @deprecated Use hasInstanceProperty or hasStaticProperty instead */
128: public function hasProperty(string $propertyName): TrinaryLogic;
129:
130: /** @deprecated Use getInstanceProperty or getStaticProperty instead */
131: public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection;
132:
133: /** @deprecated Use getUnresolvedInstancePropertyPrototype or getUnresolvedStaticPropertyPrototype instead */
134: public function getUnresolvedPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection;
135:
136: public function hasInstanceProperty(string $propertyName): TrinaryLogic;
137:
138: public function getInstanceProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection;
139:
140: /**
141: * Unlike getInstanceProperty(), this defers template type resolution.
142: * Use getInstanceProperty() in most rule implementations.
143: */
144: public function getUnresolvedInstancePropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection;
145:
146: public function hasStaticProperty(string $propertyName): TrinaryLogic;
147:
148: public function getStaticProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection;
149:
150: public function getUnresolvedStaticPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection;
151:
152: public function canCallMethods(): TrinaryLogic;
153:
154: public function hasMethod(string $methodName): TrinaryLogic;
155:
156: public function getMethod(string $methodName, ClassMemberAccessAnswerer $scope): ExtendedMethodReflection;
157:
158: /**
159: * Unlike getMethod(), this defers template type and static type resolution.
160: * Use getMethod() in most rule implementations.
161: */
162: public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAccessAnswerer $scope): UnresolvedMethodPrototypeReflection;
163:
164: public function canAccessConstants(): TrinaryLogic;
165:
166: public function hasConstant(string $constantName): TrinaryLogic;
167:
168: public function getConstant(string $constantName): ClassConstantReflection;
169:
170: public function isIterable(): TrinaryLogic;
171:
172: public function isIterableAtLeastOnce(): TrinaryLogic;
173:
174: /**
175: * Returns the count of elements as a Type (typically IntegerRangeType).
176: */
177: public function getArraySize(): Type;
178:
179: /**
180: * Works for both arrays and Traversable objects.
181: */
182: public function getIterableKeyType(): Type;
183:
184: /** @deprecated use getIterableKeyType */
185: public function getFirstIterableKeyType(): Type;
186:
187: /** @deprecated use getIterableKeyType */
188: public function getLastIterableKeyType(): Type;
189:
190: public function getIterableValueType(): Type;
191:
192: /** @deprecated use getIterableValueType */
193: public function getFirstIterableValueType(): Type;
194:
195: /** @deprecated use getIterableValueType */
196: public function getLastIterableValueType(): Type;
197:
198: public function isArray(): TrinaryLogic;
199:
200: public function isConstantArray(): TrinaryLogic;
201:
202: /**
203: * An oversized array is a constant array shape that grew too large to track
204: * precisely and was degraded to a generic array type.
205: */
206: public function isOversizedArray(): TrinaryLogic;
207:
208: /**
209: * A list is an array with sequential integer keys starting from 0 with no gaps.
210: */
211: public function isList(): TrinaryLogic;
212:
213: public function isOffsetAccessible(): TrinaryLogic;
214:
215: /**
216: * Whether accessing a non-existent offset is safe (won't cause errors).
217: * Unlike isOffsetAccessible() which checks if offset access is supported at all.
218: */
219: public function isOffsetAccessLegal(): TrinaryLogic;
220:
221: public function hasOffsetValueType(Type $offsetType): TrinaryLogic;
222:
223: public function getOffsetValueType(Type $offsetType): Type;
224:
225: /**
226: * May add a new key. When $offsetType is null, appends (like $a[] = $value).
227: *
228: * @see Type::setExistingOffsetValueType() for modifying an existing key without widening
229: */
230: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type;
231:
232: /**
233: * Unlike setOffsetValueType(), assumes the key already exists.
234: * Preserves the array shape and list type.
235: */
236: public function setExistingOffsetValueType(Type $offsetType, Type $valueType): Type;
237:
238: public function unsetOffset(Type $offsetType): Type;
239:
240: /** Models array_keys($array, $searchValue, $strict). */
241: public function getKeysArrayFiltered(Type $filterValueType, TrinaryLogic $strict): Type;
242:
243: /** Models array_keys($array). */
244: public function getKeysArray(): Type;
245:
246: /** Models array_values($array). */
247: public function getValuesArray(): Type;
248:
249: /** Models array_chunk($array, $length, $preserveKeys). */
250: public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type;
251:
252: /** Models array_fill_keys($keys, $value). */
253: public function fillKeysArray(Type $valueType): Type;
254:
255: /** Models array_flip($array). */
256: public function flipArray(): Type;
257:
258: /** Models array_intersect_key($array, ...$otherArrays). */
259: public function intersectKeyArray(Type $otherArraysType): Type;
260:
261: /** Models array_pop() effect on the array. */
262: public function popArray(): Type;
263:
264: /** Models array_reverse($array, $preserveKeys). */
265: public function reverseArray(TrinaryLogic $preserveKeys): Type;
266:
267: /** Models array_search($needle, $array, $strict). */
268: public function searchArray(Type $needleType, ?TrinaryLogic $strict = null): Type;
269:
270: /** Models array_shift() effect on the array. */
271: public function shiftArray(): Type;
272:
273: /**
274: * Models shuffle() effect on the array. Result is always a list.
275: *
276: * It's also used to model array after `sort` / `rsort` / `usort` calls.
277: */
278: public function shuffleArray(): Type;
279:
280: /** Models array_slice($array, $offset, $length, $preserveKeys). */
281: public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $preserveKeys): Type;
282:
283: /** Models array_splice() effect on the array (the modified array, not the removed portion). */
284: public function spliceArray(Type $offsetType, Type $lengthType, Type $replacementType): Type;
285:
286: /**
287: * Narrows a list-shaped array type to "size lies in $sizeType" — the
288: * type-system equivalent of `count($list) === N` / `count($list) >= N`
289: * / `count($list) in [N, M]`. Used by `TypeSpecifier` when specifying
290: * types for `count()` comparisons; the call site is responsible for
291: * gating on outer list-ness, so each implementation may assume it's
292: * narrowing a list shape.
293: *
294: * `$sizeType` is expected to be a `ConstantIntegerType` (exact size) or
295: * an `IntegerRangeType` (a min/max bound). Concrete implementations
296: * (`ConstantArrayType`, `ArrayType`) rebuild the array with a required
297: * prefix `[0, min)` and an optional middle `[min, max)` (when `max` is
298: * set), or extend with `HasOffsetValueType` accessories when the upper
299: * bound is unbounded. Non-array types return `ErrorType`.
300: */
301: public function truncateListToSize(Type $sizeType): Type;
302:
303: /**
304: * Downgrades the list-ness of the array from `Yes` to `Maybe` (e.g. for
305: * `asort`/`uksort`/etc. which preserve keys but break list ordering).
306: * Other shape information (keys, values, accessories like NonEmpty) is
307: * preserved.
308: */
309: public function makeListMaybe(): Type;
310:
311: /**
312: * Models "same keys, every value transformed" (e.g. `array_walk`,
313: * `array_map($cb, $a)`, `preg_replace*` over an array subject). Keys
314: * and accessories like list-ness / non-emptiness are preserved.
315: *
316: * @param callable(Type): Type $cb
317: */
318: public function mapValueType(callable $cb): Type;
319:
320: /**
321: * Replaces the iterable key type via `$cb($currentKeyType)`. For
322: * `ArrayType` rewrites the key type wholesale; for `ConstantArrayType`
323: * the explicit keys (which are already precise constants) are preserved
324: * — pass-through, matching the prior `TypeTraverser`-based callers.
325: * Used to widen / narrow the key type after a foreach narrowed `$key`
326: * via `is_int($key)` / `is_string($key)` checks.
327: *
328: * @param callable(Type): Type $cb
329: */
330: public function mapKeyType(callable $cb): Type;
331:
332: /**
333: * Marks every explicit key in a `ConstantArrayType` as optional (the
334: * shape can have any subset of the original keys). For non-`CAT` arrays
335: * this is a no-op — they already model arbitrary subsets. Used by
336: * `preg_replace*` over array subjects, where the callback can drop
337: * entries.
338: */
339: public function makeAllArrayKeysOptional(): Type;
340:
341: /**
342: * Models `array_change_key_case($a, $case)`. String keys are case-folded
343: * (constant ones to a specific value, general ones via accessories);
344: * non-string keys, values, accessories and list-ness are preserved.
345: * `$case` matches PHP's `CASE_LOWER` / `CASE_UPPER`; `null` means the
346: * case is non-constant and the result is the union of both folds.
347: */
348: public function changeKeyCaseArray(?int $case): Type;
349:
350: /**
351: * Models `array_filter($a)` (no callback): drops entries whose value is
352: * definitely falsey, marks possibly-falsey entries optional, keeps
353: * definitely-truthy entries unchanged. Keys are preserved; list-ness
354: * is downgraded since gaps may appear.
355: */
356: public function filterArrayRemovingFalsey(): Type;
357:
358: /** @return list<EnumCaseObjectType> */
359: public function getEnumCases(): array;
360:
361: /**
362: * Returns the single enum case this type represents, or null if not exactly one case.
363: */
364: public function getEnumCaseObject(): ?EnumCaseObjectType;
365:
366: /**
367: * Returns a list of finite values this type can take.
368: *
369: * Examples:
370: *
371: * - for bool: [true, false]
372: * - for int<0, 3>: [0, 1, 2, 3]
373: * - for enums: list of enum cases
374: * - for scalars: the scalar itself
375: *
376: * For infinite types it returns an empty array.
377: *
378: * @return list<Type>
379: */
380: public function getFiniteTypes(): array;
381:
382: /** Models the ** operator. */
383: public function exponentiate(Type $exponent): Type;
384:
385: public function isCallable(): TrinaryLogic;
386:
387: /** @return list<CallableParametersAcceptor> */
388: public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array;
389:
390: public function isCloneable(): TrinaryLogic;
391:
392: /** Models the (bool) cast. */
393: public function toBoolean(): BooleanType;
394:
395: /** Models numeric coercion for arithmetic operators. */
396: public function toNumber(): Type;
397:
398: /** Models the bitwise-not (`~$x`) operator. Returns `ErrorType` for types where `~` is undefined. */
399: public function toBitwiseNotType(): Type;
400:
401: /**
402: * Models `get_class($x)`'s return type per leaf: definite objects yield
403: * their `class-string` projection, definite non-objects yield `false`,
404: * and possibly-objects yield the union of both.
405: */
406: public function toGetClassResultType(): Type;
407:
408: /**
409: * Models the type of `$x::class`. For known final classes the literal
410: * class name is returned; for everything else an
411: * `IntersectionType[ClassString<X>, AccessoryLiteralStringType]`.
412: * `NullType` passes through (mirrors PHP's nullsafe `::class` semantics).
413: * `ReflectionProvider` is needed for the final-class lookup.
414: */
415: public function toClassConstantType(ReflectionProvider $reflectionProvider): Type;
416:
417: /**
418: * Projects a class-name-or-object `Type` (the right-hand side of
419: * `$x instanceof <expr>`) to the `ObjectType` it should be compared
420: * against. Constant class strings collapse to their `ObjectType`
421: * exactly; everything kept symbolically (object class names,
422: * `class-string<X>`) carries an uncertainty flag so the caller can
423: * fall back to `BooleanType` instead of a definite yes/no.
424: */
425: public function toObjectTypeForInstanceofCheck(): ClassNameToObjectTypeResult;
426:
427: /**
428: * Projects a class-name-or-object `Type` (the second argument of
429: * `is_a($x, $class, $allow_string)`) to the `ObjectType` to narrow
430: * `$x` against. When `$allowString` is true, the `is_a()` result also
431: * keeps the original class-string accepted alongside the object.
432: * `$allowSameClass` controls whether matching the input's own class
433: * collapses to `NeverType` for final classes (the call site's
434: * "always-true" suppression).
435: */
436: public function toObjectTypeForIsACheck(Type $objectOrClassType, bool $allowString, bool $allowSameClass): ClassNameToObjectTypeResult;
437:
438: /** Models the (int) cast. */
439: public function toInteger(): Type;
440:
441: /** Models the (float) cast. */
442: public function toFloat(): Type;
443:
444: /** Models the (string) cast. */
445: public function toString(): Type;
446:
447: /** Models the (array) cast. */
448: public function toArray(): Type;
449:
450: /**
451: * Models PHP's implicit array key coercion: floats truncated to int,
452: * booleans become 0/1, null becomes '', numeric strings become int.
453: */
454: public function toArrayKey(): Type;
455:
456: /**
457: * Returns how this type might change when passed to a typed parameter
458: * or assigned to a typed property.
459: *
460: * With $strictTypes = true: int widens to int|float (since int is accepted
461: * by float parameters in strict mode).
462: * With $strictTypes = false: additional coercions apply, e.g. Stringable
463: * objects are accepted by string parameters.
464: *
465: * Used internally to determine what types a value might be coerced to
466: * when checking parameter acceptance.
467: */
468: public function toCoercedArgumentType(bool $strictTypes): self;
469:
470: public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic;
471:
472: public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic;
473:
474: /**
475: * Is Type of a known constant value? Includes literal strings, integers, floats, true, false, null, and array shapes.
476: *
477: * Unlike isConstantScalarValue(), this also returns yes for constant array types (array shapes
478: * with known keys and values). Use this when you need to detect any constant value including arrays.
479: */
480: public function isConstantValue(): TrinaryLogic;
481:
482: /**
483: * Is Type of a known constant scalar value? Includes literal strings, integers, floats, true, false, and null.
484: *
485: * Unlike isConstantValue(), this does NOT return yes for array shapes.
486: * Use this when you specifically need scalar constants only.
487: */
488: public function isConstantScalarValue(): TrinaryLogic;
489:
490: /** @return list<ConstantScalarType> */
491: public function getConstantScalarTypes(): array;
492:
493: /** @return list<int|float|string|bool|null> */
494: public function getConstantScalarValues(): array;
495:
496: public function isNull(): TrinaryLogic;
497:
498: public function isTrue(): TrinaryLogic;
499:
500: public function isFalse(): TrinaryLogic;
501:
502: public function isBoolean(): TrinaryLogic;
503:
504: public function isFloat(): TrinaryLogic;
505:
506: public function isInteger(): TrinaryLogic;
507:
508: public function isString(): TrinaryLogic;
509:
510: public function isNumericString(): TrinaryLogic;
511:
512: /**
513: * When isDecimalIntegerString() returns yes(), the type
514: * is guaranteed to be cast to an integer in an array key.
515: * Examples of constant values covered by this type: "0", "1", "1234", "-1"
516: *
517: * When isDecimalIntegerString() returns no(), the type represents strings containing non-decimal integers and other text.
518: * These are guaranteed to stay as string in an array key.
519: * Examples of constant values covered by this type: "+1", "00", "18E+3", "1.2", "1,3", "foo"
520: */
521: public function isDecimalIntegerString(): TrinaryLogic;
522:
523: public function isNonEmptyString(): TrinaryLogic;
524:
525: /**
526: * Non-falsy string is a non-empty string that is also not '0'.
527: * Stricter subset of non-empty-string.
528: */
529: public function isNonFalsyString(): TrinaryLogic;
530:
531: /**
532: * A literal-string is a string composed entirely from string literals
533: * in the source code (not from user input). Used for SQL injection prevention.
534: */
535: public function isLiteralString(): TrinaryLogic;
536:
537: public function isLowercaseString(): TrinaryLogic;
538:
539: public function isUppercaseString(): TrinaryLogic;
540:
541: public function isClassString(): TrinaryLogic;
542:
543: public function isVoid(): TrinaryLogic;
544:
545: public function isScalar(): TrinaryLogic;
546:
547: public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType;
548:
549: /**
550: * Type narrowing methods for comparison operators.
551: * For example, for ConstantIntegerType(5), getSmallerType() returns int<min, 4>.
552: */
553: public function getSmallerType(PhpVersion $phpVersion): Type;
554:
555: public function getSmallerOrEqualType(PhpVersion $phpVersion): Type;
556:
557: public function getGreaterType(PhpVersion $phpVersion): Type;
558:
559: public function getGreaterOrEqualType(PhpVersion $phpVersion): Type;
560:
561: /**
562: * Returns actual template type for a given object.
563: *
564: * Example:
565: *
566: * @-template T
567: * class Foo {}
568: *
569: * // $fooType is Foo<int>
570: * $t = $fooType->getTemplateType(Foo::class, 'T');
571: * $t->isInteger(); // yes
572: *
573: * Returns ErrorType in case of a missing type.
574: *
575: * @param class-string $ancestorClassName
576: */
577: public function getTemplateType(string $ancestorClassName, string $templateTypeName): Type;
578:
579: /**
580: * Infers the real types of TemplateTypes found in $this, based on
581: * the received Type. E.g. if $this is array<T> and $receivedType
582: * is array<int>, infers T = int.
583: */
584: public function inferTemplateTypes(Type $receivedType): TemplateTypeMap;
585:
586: /**
587: * Returns the template types referenced by this Type, recursively.
588: *
589: * The return value is a list of TemplateTypeReferences, who contain the
590: * referenced template type as well as the variance position in which it was
591: * found.
592: *
593: * For example, calling this on array<Foo<T>,Bar> (with T a template type)
594: * will return one TemplateTypeReference for the type T.
595: *
596: * @param TemplateTypeVariance $positionVariance The variance position in
597: * which the receiver type was
598: * found.
599: *
600: * @return list<TemplateTypeReference>
601: */
602: public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array;
603:
604: /** Models abs(). */
605: public function toAbsoluteNumber(): Type;
606:
607: /**
608: * Returns a new instance with all inner types mapped through $cb.
609: * Returns the same instance if inner types did not change.
610: *
611: * Not used directly — use TypeTraverser::map() instead.
612: *
613: * @param callable(Type):Type $cb
614: */
615: public function traverse(callable $cb): Type;
616:
617: /**
618: * Like traverse(), but walks two types simultaneously.
619: *
620: * Not used directly — use SimultaneousTypeTraverser::map() instead.
621: *
622: * @param callable(Type $left, Type $right): Type $cb
623: */
624: public function traverseSimultaneously(Type $right, callable $cb): Type;
625:
626: public function toPhpDocNode(): TypeNode;
627:
628: /** @see TypeCombinator::remove() */
629: public function tryRemove(Type $typeToRemove): ?Type;
630:
631: /**
632: * Removes constant value information. E.g. 'foo' -> string, 1 -> int.
633: * Used when types become too complex to track precisely (e.g. loop iterations).
634: */
635: public function generalize(GeneralizePrecision $precision): Type;
636:
637: /**
638: * Performance optimization to skip template resolution when no templates are present.
639: */
640: public function hasTemplateOrLateResolvableType(): bool;
641:
642: }
643: