1+ <?php namespace lang ;
2+
3+ use ReflectionProperty , ReflectionType , ReflectionClass , ReturnTypeWillChange ;
4+
5+ /**
6+ * Virtual properties
7+ *
8+ * Note the "name" and "class" members are not available as they cannot
9+ * be assigned in inherited classes.
10+ *
11+ * @test net.xp_framework.unittest.reflection.VirtualMembersTest
12+ * @see https://github.com/xp-framework/rfc/issues/340
13+ * @see https://www.php.net/language.oop5.overloading#object.get
14+ * @see https://www.php.net/language.oop5.overloading#object.set
15+ * @see https://docs.phpdoc.org/latest/guide/references/phpdoc/tags/property.html
16+ */
17+ class VirtualProperty extends ReflectionProperty {
18+ private $ _class , $ _name , $ _meta ;
19+
20+ /**
21+ * Creates a new virtual property
22+ *
23+ * @param \ReflectionClass $class
24+ * @param string $name
25+ * @param var[] $meta
26+ */
27+ public function __construct ($ class , $ name , $ meta = [MODIFIER_PUBLIC , null ]) {
28+ $ this ->_class = $ class ;
29+ $ this ->_name = $ name ;
30+ $ this ->_meta = $ meta ;
31+ }
32+
33+ /** Gets name */
34+ public function getName (): string { return $ this ->_name ; }
35+
36+ /** Gets modifiers */
37+ public function getModifiers (): int { return $ this ->_meta [0 ]; }
38+
39+ /** Checks if property has a type */
40+ public function hasType (): bool { return isset ($ this ->_meta [1 ]); }
41+
42+ /** Gets type */
43+ public function getType (): ReflectionType {
44+ return new class ($ this ->_meta [1 ]) extends ReflectionType {
45+ private $ _name ;
46+ public function __construct ($ name ) { $ this ->_name = $ name ; }
47+ public function getName (): string { return $ this ->_name ; }
48+ public function allowsNull (): bool { return false ; }
49+ public function __toString () { return $ this ->_name ; }
50+ };
51+ }
52+
53+ /** Gets declaring class */
54+ public function getDeclaringClass (): ReflectionClass { return $ this ->_class ; }
55+
56+ /** Gets doc comment */
57+ #[ReturnTypeWillChange]
58+ public function getDocComment () { return false ; }
59+
60+ /** Gets whether a default value is available */
61+ public function hasDefaultValue (): bool { return false ; }
62+
63+ /** Gets default value */
64+ #[ReturnTypeWillChange]
65+ public function getDefaultValue () { return null ; }
66+
67+ /** Checks if property is a default property */
68+ public function isDefault (): bool { return false ; }
69+
70+ /** Returns whether this property is public */
71+ public function isPublic (): bool { return MODIFIER_PUBLIC === ($ this ->_meta [0 ] & MODIFIER_PUBLIC ); }
72+
73+ /** Returns whether this property is protected */
74+ public function isProtected (): bool { return MODIFIER_PROTECTED === ($ this ->_meta [0 ] & MODIFIER_PROTECTED ); }
75+
76+ /** Returns whether this property is private */
77+ public function isPrivate (): bool { return MODIFIER_PRIVATE === ($ this ->_meta [0 ] & MODIFIER_PRIVATE ); }
78+
79+ /** Returns whether this property is private */
80+ public function isStatic (): bool { return MODIFIER_STATIC === ($ this ->_meta [0 ] & MODIFIER_STATIC ); }
81+
82+ /**
83+ * Returns all attributes declared on this class property as an array of ReflectionAttribute.
84+ *
85+ * @param ?string $name
86+ * @param int $flags
87+ * @return \ReflectionAttribute[]
88+ */
89+ public function getAttributes (string $ name = null , int $ flags = 0 ): array {
90+ return [];
91+ }
92+
93+ /**
94+ * Sets accessible flag
95+ *
96+ * @param bool $flag
97+ * @return void
98+ */
99+ #[ReturnTypeWillChange]
100+ public function setAccessible ($ flag ) { /* NOOP */ }
101+
102+ /**
103+ * Checks whether a property is initialized.
104+ *
105+ * @param ?object $instance
106+ * @return bool
107+ */
108+ public function isInitialized ($ instance = null ): bool {
109+ return null !== $ instance ->__get ($ this ->_name );
110+ }
111+
112+ /**
113+ * Gets this property's value
114+ *
115+ * @param ?object $instance
116+ * @return var
117+ */
118+ #[ReturnTypeWillChange]
119+ public function getValue ($ instance = null ) {
120+ return $ instance ->__get ($ this ->_name );
121+ }
122+
123+ /**
124+ * Sets this property's value
125+ *
126+ * @param ?object $instance
127+ * @param var $value
128+ * @return void
129+ */
130+ #[ReturnTypeWillChange]
131+ public function setValue ($ instance = null , $ value = null ) {
132+ $ instance ->__set ($ this ->_name , $ value );
133+ }
134+
135+ /**
136+ * Compares to property instances
137+ *
138+ * @param \ReflectionProperty $a
139+ * @param \ReflectionProperty $b
140+ * @return int
141+ */
142+ public static function compare ($ a , $ b ) {
143+ if ($ a instanceof self && $ b instanceof self) {
144+ $ r = $ a ->_class <=> $ b ->_class ;
145+ return 0 === $ r ? $ a ->_name <=> $ b ->_name : $ r ;
146+ } else if ($ a instanceof self) {
147+ $ r = $ a ->_class <=> $ b ->class ;
148+ return 0 === $ r ? $ a ->_name <=> $ b ->name : $ r ;
149+ } else if ($ b instanceof self) {
150+ $ r = $ a ->class <=> $ b ->_class ;
151+ return 0 === $ r ? $ a ->name <=> $ b ->_name : $ r ;
152+ } else {
153+ $ r = $ a ->class <=> $ b ->class ;
154+ return 0 === $ r ? $ a ->name <=> $ b ->name : $ r ;
155+ }
156+ }
157+ }
0 commit comments