1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Accessory;
4:
5: use PHPStan\TrinaryLogic;
6: use PHPStan\Type\CompoundType;
7: use PHPStan\Type\Constant\ConstantArrayType;
8: use PHPStan\Type\Constant\ConstantIntegerType;
9: use PHPStan\Type\Constant\ConstantStringType;
10: use PHPStan\Type\ErrorType;
11: use PHPStan\Type\FloatType;
12: use PHPStan\Type\GeneralizePrecision;
13: use PHPStan\Type\IntegerType;
14: use PHPStan\Type\IntersectionType;
15: use PHPStan\Type\StringType;
16: use PHPStan\Type\Traits\NonArrayTypeTrait;
17: use PHPStan\Type\Traits\NonCallableTypeTrait;
18: use PHPStan\Type\Traits\NonGenericTypeTrait;
19: use PHPStan\Type\Traits\NonIterableTypeTrait;
20: use PHPStan\Type\Traits\NonObjectTypeTrait;
21: use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
22: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
23: use PHPStan\Type\Type;
24: use PHPStan\Type\TypeCombinator;
25: use PHPStan\Type\UnionType;
26: use PHPStan\Type\VerbosityLevel;
27:
28: class AccessoryNumericStringType implements CompoundType, AccessoryType
29: {
30:
31: use NonArrayTypeTrait;
32: use NonCallableTypeTrait;
33: use NonObjectTypeTrait;
34: use NonIterableTypeTrait;
35: use UndecidedBooleanTypeTrait;
36: use UndecidedComparisonCompoundTypeTrait;
37: use NonGenericTypeTrait;
38:
39: /** @api */
40: public function __construct()
41: {
42: }
43:
44: public function getReferencedClasses(): array
45: {
46: return [];
47: }
48:
49: public function getConstantStrings(): array
50: {
51: return [];
52: }
53:
54: public function accepts(Type $type, bool $strictTypes): TrinaryLogic
55: {
56: if ($type instanceof CompoundType) {
57: return $type->isAcceptedBy($this, $strictTypes);
58: }
59:
60: return $type->isNumericString();
61: }
62:
63: public function isSuperTypeOf(Type $type): TrinaryLogic
64: {
65: if ($type instanceof CompoundType) {
66: return $type->isSubTypeOf($this);
67: }
68:
69: if ($this->equals($type)) {
70: return TrinaryLogic::createYes();
71: }
72:
73: return $type->isNumericString();
74: }
75:
76: public function isSubTypeOf(Type $otherType): TrinaryLogic
77: {
78: if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
79: return $otherType->isSuperTypeOf($this);
80: }
81:
82: return $otherType->isNumericString()
83: ->and($otherType instanceof self ? TrinaryLogic::createYes() : TrinaryLogic::createMaybe());
84: }
85:
86: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic
87: {
88: if ($acceptingType->isNonFalsyString()->yes()) {
89: return TrinaryLogic::createMaybe();
90: }
91:
92: if ($acceptingType->isNonEmptyString()->yes()) {
93: return TrinaryLogic::createYes();
94: }
95:
96: return $this->isSubTypeOf($acceptingType);
97: }
98:
99: public function equals(Type $type): bool
100: {
101: return $type instanceof self;
102: }
103:
104: public function describe(VerbosityLevel $level): string
105: {
106: return 'numeric-string';
107: }
108:
109: public function isOffsetAccessible(): TrinaryLogic
110: {
111: return TrinaryLogic::createYes();
112: }
113:
114: public function hasOffsetValueType(Type $offsetType): TrinaryLogic
115: {
116: return (new IntegerType())->isSuperTypeOf($offsetType)->and(TrinaryLogic::createMaybe());
117: }
118:
119: public function getOffsetValueType(Type $offsetType): Type
120: {
121: if ($this->hasOffsetValueType($offsetType)->no()) {
122: return new ErrorType();
123: }
124:
125: return new StringType();
126: }
127:
128: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
129: {
130: return $this;
131: }
132:
133: public function unsetOffset(Type $offsetType): Type
134: {
135: return new ErrorType();
136: }
137:
138: public function toNumber(): Type
139: {
140: return new UnionType([
141: $this->toInteger(),
142: $this->toFloat(),
143: ]);
144: }
145:
146: public function toInteger(): Type
147: {
148: return new IntegerType();
149: }
150:
151: public function toFloat(): Type
152: {
153: return new FloatType();
154: }
155:
156: public function toString(): Type
157: {
158: return $this;
159: }
160:
161: public function toArray(): Type
162: {
163: return new ConstantArrayType(
164: [new ConstantIntegerType(0)],
165: [$this],
166: [1],
167: [],
168: true,
169: );
170: }
171:
172: public function toArrayKey(): Type
173: {
174: return new IntegerType();
175: }
176:
177: public function isNull(): TrinaryLogic
178: {
179: return TrinaryLogic::createNo();
180: }
181:
182: public function isTrue(): TrinaryLogic
183: {
184: return TrinaryLogic::createNo();
185: }
186:
187: public function isFalse(): TrinaryLogic
188: {
189: return TrinaryLogic::createNo();
190: }
191:
192: public function isBoolean(): TrinaryLogic
193: {
194: return TrinaryLogic::createNo();
195: }
196:
197: public function isFloat(): TrinaryLogic
198: {
199: return TrinaryLogic::createNo();
200: }
201:
202: public function isInteger(): TrinaryLogic
203: {
204: return TrinaryLogic::createNo();
205: }
206:
207: public function isString(): TrinaryLogic
208: {
209: return TrinaryLogic::createYes();
210: }
211:
212: public function isNumericString(): TrinaryLogic
213: {
214: return TrinaryLogic::createYes();
215: }
216:
217: public function isNonEmptyString(): TrinaryLogic
218: {
219: return TrinaryLogic::createYes();
220: }
221:
222: public function isNonFalsyString(): TrinaryLogic
223: {
224: return TrinaryLogic::createMaybe();
225: }
226:
227: public function isLiteralString(): TrinaryLogic
228: {
229: return TrinaryLogic::createMaybe();
230: }
231:
232: public function isClassStringType(): TrinaryLogic
233: {
234: return TrinaryLogic::createNo();
235: }
236:
237: public function isVoid(): TrinaryLogic
238: {
239: return TrinaryLogic::createNo();
240: }
241:
242: public function isScalar(): TrinaryLogic
243: {
244: return TrinaryLogic::createYes();
245: }
246:
247: public function traverse(callable $cb): Type
248: {
249: return $this;
250: }
251:
252: public function generalize(GeneralizePrecision $precision): Type
253: {
254: return new StringType();
255: }
256:
257: public static function __set_state(array $properties): Type
258: {
259: return new self();
260: }
261:
262: public function tryRemove(Type $typeToRemove): ?Type
263: {
264: if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '0') {
265: return TypeCombinator::intersect($this, new AccessoryNonFalsyStringType());
266: }
267:
268: return null;
269: }
270:
271: }
272: