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