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