1+ <?php
2+
3+ namespace PHPStan \Type ;
4+
5+ use PHPStan \PhpDocParser \Ast \Type \GenericTypeNode ;
6+ use PHPStan \PhpDocParser \Ast \Type \IdentifierTypeNode ;
7+ use PHPStan \PhpDocParser \Ast \Type \TypeNode ;
8+ use PHPStan \Type \Constant \ConstantStringType ;
9+ use PHPStan \Type \Generic \TemplateTypeVariance ;
10+ use PHPStan \Type \Traits \LateResolvableTypeTrait ;
11+ use PHPStan \Type \Traits \NonGeneralizableTypeTrait ;
12+
13+ class PropertyOfType implements CompoundType, LateResolvableType
14+ {
15+
16+ use LateResolvableTypeTrait;
17+ use NonGeneralizableTypeTrait;
18+
19+ public function __construct (private Type $ type )
20+ {
21+ }
22+
23+ public function getType (): Type
24+ {
25+ return $ this ->type ;
26+ }
27+
28+ public function getReferencedClasses (): array
29+ {
30+ return $ this ->type ->getReferencedClasses ();
31+ }
32+
33+ public function getReferencedTemplateTypes (TemplateTypeVariance $ positionVariance ): array
34+ {
35+ return $ this ->type ->getReferencedTemplateTypes ($ positionVariance );
36+ }
37+
38+ public function equals (Type $ type ): bool
39+ {
40+ return $ type instanceof self
41+ && $ this ->type ->equals ($ type ->type );
42+ }
43+
44+ public function describe (VerbosityLevel $ level ): string
45+ {
46+ return sprintf ('property-of<%s> ' , $ this ->type ->describe ($ level ));
47+ }
48+
49+ public function isResolvable (): bool
50+ {
51+ return !TypeUtils::containsTemplateType ($ this ->type );
52+ }
53+
54+ protected function getResult (): Type
55+ {
56+
57+ $ classReflection = null ;
58+
59+ if ($ this ->type instanceof TypeWithClassName) {
60+ $ classReflection = $ this ->type ->getClassReflection ();
61+ }
62+
63+ if ($ classReflection !== null ) {
64+
65+ $ propertiesReflection = $ classReflection ->getNativeReflection ()->getProperties ();
66+
67+ // get the names of the properties
68+ // and build a union type from them
69+ $ propertyNames = array_map (
70+ fn ($ property ) => new ConstantStringType ($ property ->getName ()),
71+ $ propertiesReflection
72+ );
73+
74+ return new UnionType ($ propertyNames );
75+
76+ }
77+
78+ return new MixedType ();
79+ }
80+
81+ /**
82+ * @param callable(Type): Type $cb
83+ */
84+ public function traverse (callable $ cb ): Type
85+ {
86+ $ type = $ cb ($ this ->type );
87+
88+ if ($ this ->type === $ type ) {
89+ return $ this ;
90+ }
91+
92+ return new self ($ type );
93+ }
94+
95+ public function traverseSimultaneously (Type $ right , callable $ cb ): Type
96+ {
97+ if (!$ right instanceof self) {
98+ return $ this ;
99+ }
100+
101+ $ type = $ cb ($ this ->type , $ right ->type );
102+
103+ if ($ this ->type === $ type ) {
104+ return $ this ;
105+ }
106+
107+ return new self ($ type );
108+ }
109+
110+ public function toPhpDocNode (): TypeNode
111+ {
112+ return new GenericTypeNode (new IdentifierTypeNode ('property-of ' ), [$ this ->type ->toPhpDocNode ()]);
113+ }
114+
115+ }
0 commit comments