1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type;
4:
5: use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
6: use PHPStan\PhpDocParser\Ast\Type\TypeNode;
7: use PHPStan\Reflection\ClassReflection;
8: use PHPStan\Reflection\ReflectionProviderStaticAccessor;
9: use PHPStan\TrinaryLogic;
10: use function sprintf;
11:
12: /** @api */
13: class ThisType extends StaticType
14: {
15:
16: /**
17: * @api
18: */
19: public function __construct(
20: ClassReflection $classReflection,
21: ?Type $subtractedType = null,
22: )
23: {
24: parent::__construct($classReflection, $subtractedType);
25: }
26:
27: public function changeBaseClass(ClassReflection $classReflection): StaticType
28: {
29: return new self($classReflection, $this->getSubtractedType());
30: }
31:
32: public function describe(VerbosityLevel $level): string
33: {
34: return sprintf('$this(%s)', $this->getStaticObjectType()->describe($level));
35: }
36:
37: public function isSuperTypeOf(Type $type): TrinaryLogic
38: {
39: if ($type instanceof self) {
40: return $this->getStaticObjectType()->isSuperTypeOf($type);
41: }
42:
43: if ($type instanceof CompoundType) {
44: return $type->isSubTypeOf($this);
45: }
46:
47: $parent = new parent($this->getClassReflection(), $this->getSubtractedType());
48:
49: return $parent->isSuperTypeOf($type)->and(TrinaryLogic::createMaybe());
50: }
51:
52: public function changeSubtractedType(?Type $subtractedType): Type
53: {
54: $type = parent::changeSubtractedType($subtractedType);
55: if ($type instanceof parent) {
56: return new self($type->getClassReflection(), $subtractedType);
57: }
58:
59: return $type;
60: }
61:
62: public function traverse(callable $cb): Type
63: {
64: $subtractedType = $this->getSubtractedType() !== null ? $cb($this->getSubtractedType()) : null;
65:
66: if ($subtractedType !== $this->getSubtractedType()) {
67: return new self(
68: $this->getClassReflection(),
69: $subtractedType,
70: );
71: }
72:
73: return $this;
74: }
75:
76: public function traverseSimultaneously(Type $right, callable $cb): Type
77: {
78: if ($this->getSubtractedType() === null) {
79: return $this;
80: }
81:
82: return new self($this->getClassReflection());
83: }
84:
85: public function toPhpDocNode(): TypeNode
86: {
87: return new ThisTypeNode();
88: }
89:
90: /**
91: * @param mixed[] $properties
92: */
93: public static function __set_state(array $properties): Type
94: {
95: $reflectionProvider = ReflectionProviderStaticAccessor::getInstance();
96: if ($reflectionProvider->hasClass($properties['baseClass'])) {
97: return new self($reflectionProvider->getClass($properties['baseClass']), $properties['subtractedType'] ?? null);
98: }
99:
100: return new ErrorType();
101: }
102:
103: }
104: