| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | declare(strict_types=1); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | namespace ProxyManager\ProxyGenerator\Util; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | use InvalidArgumentException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | use Laminas\Code\Generator\PropertyGenerator; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | use function sprintf; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  * Generates code necessary to simulate a fatal error in case of unauthorized | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |  * access to class members in magic methods even when in child classes and dealing | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  * with protected members. | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 15 |  |  |  */ | 
            
                                                                        
                            
            
                                    
            
            
                | 16 |  |  | class PublicScopeSimulator | 
            
                                                                        
                            
            
                                    
            
            
                | 17 |  |  | { | 
            
                                                                        
                            
            
                                    
            
            
                | 18 |  |  |     public const OPERATION_SET   = 'set'; | 
            
                                                                        
                            
            
                                    
            
            
                | 19 |  |  |     public const OPERATION_GET   = 'get'; | 
            
                                                                        
                            
            
                                    
            
            
                | 20 |  |  |     public const OPERATION_ISSET = 'isset'; | 
            
                                                                        
                            
            
                                    
            
            
                | 21 |  |  |     public const OPERATION_UNSET = 'unset'; | 
            
                                                                        
                            
            
                                    
            
            
                | 22 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 23 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 24 |  |  |      * Generates code for simulating access to a property from the scope that is accessing a proxy. | 
            
                                                                        
                            
            
                                    
            
            
                | 25 |  |  |      * This is done by introspecting `debug_backtrace()` and then binding a closure to the scope | 
            
                                                                        
                            
            
                                    
            
            
                | 26 |  |  |      * of the parent caller. | 
            
                                                                        
                            
            
                                    
            
            
                | 27 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 28 |  |  |      * @param string            $operationType      operation to execute: one of 'get', 'set', 'isset' or 'unset' | 
            
                                                                        
                            
            
                                    
            
            
                | 29 |  |  |      * @param string            $nameParameter      name of the `name` parameter of the magic method | 
            
                                                                        
                            
            
                                    
            
            
                | 30 |  |  |      * @param string|null       $valueParameter     name of the `value` parameter of the magic method | 
            
                                                                        
                            
            
                                    
            
            
                | 31 |  |  |      * @param PropertyGenerator $valueHolder        name of the property containing the target object from which | 
            
                                                                        
                            
            
                                    
            
            
                | 32 |  |  |      *                                              to read the property. `$this` if none provided | 
            
                                                                        
                            
            
                                    
            
            
                | 33 |  |  |      * @param string|null       $returnPropertyName name of the property to which we want to assign the result of | 
            
                                                                        
                            
            
                                    
            
            
                | 34 |  |  |      *                                              the operation. Return directly if none provided | 
            
                                                                        
                            
            
                                    
            
            
                | 35 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 36 |  |  |      * @throws InvalidArgumentException | 
            
                                                                        
                            
            
                                    
            
            
                | 37 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 | 8 |  |     public static function getPublicAccessSimulationCode( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |         string $operationType, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |         string $nameParameter, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |         ?string $valueParameter = null, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |         ?PropertyGenerator $valueHolder = null, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |         ?string $returnPropertyName = null | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |     ) : string { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 | 8 |  |         $byRef  = self::getByRefReturnValue($operationType); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 | 8 |  |         $value  = $operationType === self::OPERATION_SET ? ', $value' : ''; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 | 8 |  |         $target = '$this'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 | 8 |  |         if ($valueHolder) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 | 1 |  |             $target = '$this->' . $valueHolder->getName(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |         return '$realInstanceReflection = new \\ReflectionClass(get_parent_class($this));' . "\n\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 | 8 |  |             . 'if (! $realInstanceReflection->hasProperty($' . $nameParameter . ')) {' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 | 8 |  |             . '    $targetObject = ' . $target . ';' . "\n\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 | 8 |  |             . self::getUndefinedPropertyNotice($operationType, $nameParameter) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 | 8 |  |             . '    ' . self::getOperation($operationType, $nameParameter, $valueParameter) . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 | 6 |  |             . "    return;\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 | 6 |  |             . '}' . "\n\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 | 6 |  |             . '$targetObject = ' . self::getTargetObject($valueHolder) . ";\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 | 6 |  |             . '$accessor = function ' . $byRef . '() use ($targetObject, $name' . $value . ') {' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 | 6 |  |             . '    ' . self::getOperation($operationType, $nameParameter, $valueParameter) . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 | 6 |  |             . "};\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 | 6 |  |             . self::getScopeReBind() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |             . ( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 | 6 |  |                 $returnPropertyName | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 | 5 |  |                     ? '$' . $returnPropertyName . ' = ' . $byRef . '$accessor();' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 | 6 |  |                     : '$returnValue = ' . $byRef . '$accessor();' . "\n\n" . 'return $returnValue;' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |             ); | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 70 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 71 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 72 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 73 |  |  |      * This will generate code that triggers a notice if access is attempted on a non-existing property | 
            
                                                                        
                            
            
                                    
            
            
                | 74 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |     private static function getUndefinedPropertyNotice(string $operationType, string $nameParameter) : string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 | 8 |  |         if ($operationType !== self::OPERATION_GET) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |             return ''; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 | 8 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 | 6 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |         return '    $backtrace = debug_backtrace(false);' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |             . '    trigger_error(' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |             . '        sprintf(' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |             . '            \'Undefined property: %s::$%s in %s on line %s\',' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |             . '            get_parent_class($this),' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |             . '            $' . $nameParameter . ',' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |             . '            $backtrace[0][\'file\'],' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 | 2 |  |             . '            $backtrace[0][\'line\']' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 | 2 |  |             . '        ),' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 | 2 |  |             . '        \E_USER_NOTICE' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 | 2 |  |             . '    );' . "\n"; | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 92 | 2 |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 93 | 2 |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 94 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 95 |  |  |      * Defines whether the given operation produces a reference. | 
            
                                                                        
                            
            
                                    
            
            
                | 96 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 97 |  |  |      * Note: if the object is a wrapper, the wrapped instance is accessed directly. If the object | 
            
                                                                        
                            
            
                                    
            
            
                | 98 |  |  |      * is a ghost or the proxy has no wrapper, then an instance of the parent class is created via | 
            
                                                                        
                            
            
                                    
            
            
                | 99 |  |  |      * on-the-fly unserialization | 
            
                                                                        
                            
            
                                    
            
            
                | 100 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |     private static function getByRefReturnValue(string $operationType) : string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 | 8 |  |         return $operationType === self::OPERATION_GET || $operationType === self::OPERATION_SET ? '& ' : ''; | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 104 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 105 | 8 |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 106 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 107 |  |  |      * Retrieves the logic to fetch the object on which access should be attempted | 
            
                                                                        
                            
            
                                    
            
            
                | 108 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |     private static function getTargetObject(?PropertyGenerator $valueHolder = null) : string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |         if ($valueHolder) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |             return '$this->' . $valueHolder->getName(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 | 6 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 | 6 |  |         return '$realInstanceReflection->newInstanceWithoutConstructor()'; | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 116 | 1 |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 117 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 118 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 119 | 5 |  |      * @throws InvalidArgumentException | 
            
                                                                        
                            
            
                                    
            
            
                | 120 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |     private static function getOperation(string $operationType, string $nameParameter, ?string $valueParameter) : string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |         switch ($operationType) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |             case self::OPERATION_GET: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 | 8 |  |                 return 'return $targetObject->$' . $nameParameter . ';'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |             case self::OPERATION_SET: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |                 if ($valueParameter === null) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 | 8 |  |                     throw new InvalidArgumentException('Parameter $valueParameter not provided'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 | 2 |  |                 } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 | 6 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 | 3 |  |                 return 'return $targetObject->$' . $nameParameter . ' = $' . $valueParameter . ';'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 | 1 |  |             case self::OPERATION_ISSET: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |                 return 'return isset($targetObject->$' . $nameParameter . ');'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |             case self::OPERATION_UNSET: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 | 2 |  |                 return 'unset($targetObject->$' . $nameParameter . ');'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 | 3 |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 | 1 |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 | 2 |  |         throw new InvalidArgumentException(sprintf('Invalid operation "%s" provided', $operationType)); | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 139 | 1 |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 140 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 141 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 142 | 1 |  |      * Generates code to bind operations to the parent scope | 
            
                                                                        
                            
            
                                    
            
            
                | 143 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |     private static function getScopeReBind() : string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |         return '$backtrace = debug_backtrace(true);' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |             . '$scopeObject = isset($backtrace[1][\'object\'])' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |             . ' ? $backtrace[1][\'object\'] : new \ProxyManager\Stub\EmptyClassStub();' . "\n" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 | 6 |  |             . '$accessor = $accessor->bindTo($scopeObject, get_class($scopeObject));' . "\n"; | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 150 |  |  |     } | 
            
                                                        
            
                                    
            
            
                | 151 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 152 |  |  |  |