1 | <?php |
||
23 | class MagicGet extends MagicMethodGenerator |
||
24 | { |
||
25 | private string $callParentTemplate = <<<'PHP' |
||
|
|||
26 | $this->%s && ! $this->%s && $this->%s('__get', array('name' => $name)); |
||
27 | |||
28 | if (isset(self::$%s[$name])) { |
||
29 | return $this->$name; |
||
30 | } |
||
31 | |||
32 | if (isset(self::$%s[$name])) { |
||
33 | if ($this->%s) { |
||
34 | return $this->$name; |
||
35 | } |
||
36 | |||
37 | // check protected property access via compatible class |
||
38 | $callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); |
||
39 | $caller = isset($callers[1]) ? $callers[1] : []; |
||
40 | $object = isset($caller['object']) ? $caller['object'] : ''; |
||
41 | $expectedType = self::$%s[$name]; |
||
42 | |||
43 | if ($object instanceof $expectedType) { |
||
44 | return $this->$name; |
||
45 | } |
||
46 | |||
47 | $class = isset($caller['class']) ? $caller['class'] : ''; |
||
48 | |||
49 | if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') { |
||
50 | return $this->$name; |
||
51 | } |
||
52 | } elseif (isset(self::$%s[$name])) { |
||
53 | // check private property access via same class |
||
54 | $callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); |
||
55 | $caller = isset($callers[1]) ? $callers[1] : []; |
||
56 | $class = isset($caller['class']) ? $caller['class'] : ''; |
||
57 | |||
58 | static $accessorCache = []; |
||
59 | |||
60 | if (isset(self::$%s[$name][$class])) { |
||
61 | $cacheKey = $class . '#' . $name; |
||
62 | $accessor = isset($accessorCache[$cacheKey]) |
||
63 | ? $accessorCache[$cacheKey] |
||
64 | : $accessorCache[$cacheKey] = \Closure::bind(function & ($instance) use ($name) { |
||
65 | return $instance->$name; |
||
66 | }, null, $class); |
||
67 | |||
68 | return $accessor($this); |
||
69 | } |
||
70 | |||
71 | if ($this->%s || 'ReflectionProperty' === $class) { |
||
72 | $tmpClass = key(self::$%s[$name]); |
||
73 | $cacheKey = $tmpClass . '#' . $name; |
||
74 | $accessor = isset($accessorCache[$cacheKey]) |
||
75 | ? $accessorCache[$cacheKey] |
||
76 | : $accessorCache[$cacheKey] = \Closure::bind(function & ($instance) use ($name) { |
||
77 | return $instance->$name; |
||
78 | }, null, $tmpClass); |
||
79 | |||
80 | return $accessor($this); |
||
81 | } |
||
82 | } |
||
83 | |||
84 | %s |
||
85 | PHP; |
||
86 | |||
87 | /** |
||
88 | * @throws InvalidArgumentException |
||
89 | */ |
||
90 | public function __construct( |
||
91 | ReflectionClass $originalClass, |
||
92 | PropertyGenerator $initializerProperty, |
||
93 | MethodGenerator $callInitializer, |
||
94 | 2 | PublicPropertiesMap $publicProperties, |
|
95 | ProtectedPropertiesMap $protectedProperties, |
||
96 | PrivatePropertiesMap $privateProperties, |
||
97 | InitializationTracker $initializationTracker |
||
98 | ) { |
||
99 | parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]); |
||
100 | |||
101 | $override = $originalClass->hasMethod('__get'); |
||
102 | |||
103 | 2 | $parentAccess = 'return parent::__get($name);'; |
|
104 | |||
105 | 2 | if (! $override) { |
|
106 | $parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode( |
||
107 | 2 | PublicScopeSimulator::OPERATION_GET, |
|
108 | 'name' |
||
109 | 2 | ); |
|
110 | 1 | } |
|
111 | 1 | ||
112 | 1 | $this->setBody(sprintf( |
|
113 | $this->callParentTemplate, |
||
114 | $initializerProperty->getName(), |
||
115 | $initializationTracker->getName(), |
||
116 | 2 | $callInitializer->getName(), |
|
117 | 2 | $publicProperties->getName(), |
|
118 | 2 | $protectedProperties->getName(), |
|
119 | 2 | $initializationTracker->getName(), |
|
120 | 2 | $protectedProperties->getName(), |
|
121 | 2 | $privateProperties->getName(), |
|
122 | 2 | $privateProperties->getName(), |
|
123 | 2 | $initializationTracker->getName(), |
|
124 | 2 | $privateProperties->getName(), |
|
125 | 2 | $parentAccess |
|
126 | 2 | )); |
|
127 | 2 | } |
|
128 | } |
||
129 |