1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Accessory;
4:
5: use PHPStan\Reflection\ClassMemberAccessAnswerer;
6: use PHPStan\Reflection\TrivialParametersAcceptor;
7: use PHPStan\TrinaryLogic;
8: use PHPStan\Type\CompoundType;
9: use PHPStan\Type\IntersectionType;
10: use PHPStan\Type\Traits\NonGeneralizableTypeTrait;
11: use PHPStan\Type\Traits\NonGenericTypeTrait;
12: use PHPStan\Type\Traits\NonRemoveableTypeTrait;
13: use PHPStan\Type\Traits\ObjectTypeTrait;
14: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
15: use PHPStan\Type\Type;
16: use PHPStan\Type\UnionType;
17: use PHPStan\Type\VerbosityLevel;
18: use function sprintf;
19:
20: class HasPropertyType implements AccessoryType, CompoundType
21: {
22:
23: use ObjectTypeTrait;
24: use NonGenericTypeTrait;
25: use UndecidedComparisonCompoundTypeTrait;
26: use NonRemoveableTypeTrait;
27: use NonGeneralizableTypeTrait;
28:
29: /** @api */
30: public function __construct(private string $propertyName)
31: {
32: }
33:
34: /**
35: * @return string[]
36: */
37: public function getReferencedClasses(): array
38: {
39: return [];
40: }
41:
42: public function getConstantStrings(): array
43: {
44: return [];
45: }
46:
47: public function getPropertyName(): string
48: {
49: return $this->propertyName;
50: }
51:
52: public function accepts(Type $type, bool $strictTypes): TrinaryLogic
53: {
54: return TrinaryLogic::createFromBoolean($this->equals($type));
55: }
56:
57: public function isSuperTypeOf(Type $type): TrinaryLogic
58: {
59: return $type->hasProperty($this->propertyName);
60: }
61:
62: public function isSubTypeOf(Type $otherType): TrinaryLogic
63: {
64: if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
65: return $otherType->isSuperTypeOf($this);
66: }
67:
68: if ($otherType instanceof self) {
69: $limit = TrinaryLogic::createYes();
70: } else {
71: $limit = TrinaryLogic::createMaybe();
72: }
73:
74: return $limit->and($otherType->hasProperty($this->propertyName));
75: }
76:
77: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic
78: {
79: return $this->isSubTypeOf($acceptingType);
80: }
81:
82: public function equals(Type $type): bool
83: {
84: return $type instanceof self
85: && $this->propertyName === $type->propertyName;
86: }
87:
88: public function describe(VerbosityLevel $level): string
89: {
90: return sprintf('hasProperty(%s)', $this->propertyName);
91: }
92:
93: public function hasProperty(string $propertyName): TrinaryLogic
94: {
95: if ($this->propertyName === $propertyName) {
96: return TrinaryLogic::createYes();
97: }
98:
99: return TrinaryLogic::createMaybe();
100: }
101:
102: public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope): array
103: {
104: return [new TrivialParametersAcceptor()];
105: }
106:
107: public function traverse(callable $cb): Type
108: {
109: return $this;
110: }
111:
112: public static function __set_state(array $properties): Type
113: {
114: return new self($properties['propertyName']);
115: }
116:
117: }
118: