[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /* 3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14 * 15 * This software consists of voluntary contributions made by many individuals 16 * and is licensed under the MIT license. 17 */ 18 19 namespace ProxyManager\ProxyGenerator\Util; 20 21 use Zend\Code\Generator\PropertyGenerator; 22 23 /** 24 * Generates code necessary to simulate a fatal error in case of unauthorized 25 * access to class members in magic methods even when in child classes and dealing 26 * with protected members. 27 * 28 * @author Marco Pivetta <ocramius@gmail.com> 29 * @license MIT 30 */ 31 class PublicScopeSimulator 32 { 33 const OPERATION_SET = 'set'; 34 const OPERATION_GET = 'get'; 35 const OPERATION_ISSET = 'isset'; 36 const OPERATION_UNSET = 'unset'; 37 38 /** 39 * Generates code for simulating access to a property from the scope that is accessing a proxy. 40 * This is done by introspecting `debug_backtrace()` and then binding a closure to the scope 41 * of the parent caller. 42 * 43 * @param string $operationType operation to execute: one of 'get', 'set', 'isset' or 'unset' 44 * @param string $nameParameter name of the `name` parameter of the magic method 45 * @param string|null $valueParameter name of the `value` parameter of the magic method 46 * @param PropertyGenerator $valueHolder name of the property containing the target object from which 47 * to read the property. `$this` if none provided 48 * @param string|null $returnPropertyName name of the property to which we want to assign the result of 49 * the operation. Return directly if none provided 50 * 51 * @return string 52 * 53 * @throws \InvalidArgumentException 54 */ 55 public static function getPublicAccessSimulationCode( 56 $operationType, 57 $nameParameter, 58 $valueParameter = null, 59 PropertyGenerator $valueHolder = null, 60 $returnPropertyName = null 61 ) { 62 $byRef = self::getByRefReturnValue($operationType); 63 $value = static::OPERATION_SET === $operationType ? ', $value' : ''; 64 $target = '$this'; 65 66 if ($valueHolder) { 67 $target = '$this->' . $valueHolder->getName(); 68 } 69 70 return '$realInstanceReflection = new \\ReflectionClass(get_parent_class($this));' . "\n\n" 71 . 'if (! $realInstanceReflection->hasProperty($' . $nameParameter . ')) {' . "\n" 72 . ' $targetObject = ' . $target . ';' . "\n\n" 73 . self::getUndefinedPropertyNotice($operationType, $nameParameter) 74 . ' ' . self::getOperation($operationType, $nameParameter, $valueParameter) . ";\n" 75 . " return;\n" 76 . '}' . "\n\n" 77 . '$targetObject = ' . self::getTargetObject($valueHolder) . ";\n" 78 . '$accessor = function ' . $byRef . '() use ($targetObject, $name' . $value . ') {' . "\n" 79 . ' ' . self::getOperation($operationType, $nameParameter, $valueParameter) . "\n" 80 . "};\n" 81 . self::getScopeReBind() 82 . ( 83 $returnPropertyName 84 ? '$' . $returnPropertyName . ' = ' . $byRef . '$accessor();' 85 : '$returnValue = ' . $byRef . '$accessor();' . "\n\n" . 'return $returnValue;' 86 ); 87 } 88 89 /** 90 * This will generate code that triggers a notice if access is attempted on a non-existing property 91 * 92 * @param string $operationType 93 * @param string $nameParameter 94 * 95 * @return string 96 */ 97 private static function getUndefinedPropertyNotice($operationType, $nameParameter) 98 { 99 if (static::OPERATION_GET !== $operationType) { 100 return ''; 101 } 102 103 // 104 return ' $backtrace = debug_backtrace(false);' . "\n" 105 . ' trigger_error(\'Undefined property: \' . get_parent_class($this) . \'::$\' . $' 106 . $nameParameter 107 . ' . \' in \' . $backtrace[0][\'file\'] . \' on line \' . $backtrace[0][\'line\'], \E_USER_NOTICE);' 108 . "\n"; 109 } 110 111 /** 112 * Defines whether the given operation produces a reference. 113 * 114 * Note: if the object is a wrapper, the wrapped instance is accessed directly. If the object 115 * is a ghost or the proxy has no wrapper, then an instance of the parent class is created via 116 * on-the-fly unserialization 117 * 118 * @param string $operationType 119 * 120 * @return string 121 */ 122 private static function getByRefReturnValue($operationType) 123 { 124 return (static::OPERATION_GET === $operationType || static::OPERATION_SET === $operationType) ? '& ' : ''; 125 } 126 127 /** 128 * Retrieves the logic to fetch the object on which access should be attempted 129 * 130 * @param PropertyGenerator $valueHolder 131 * 132 * @return string 133 */ 134 private static function getTargetObject(PropertyGenerator $valueHolder = null) 135 { 136 if ($valueHolder) { 137 return '$this->' . $valueHolder->getName(); 138 } 139 140 return 'unserialize(sprintf(\'O:%d:"%s":0:{}\', strlen(get_parent_class($this)), get_parent_class($this)))'; 141 } 142 143 /** 144 * @param string $operationType 145 * @param string $nameParameter 146 * @param string|null $valueParameter 147 * 148 * @return string 149 * 150 * @throws \InvalidArgumentException 151 */ 152 private static function getOperation($operationType, $nameParameter, $valueParameter) 153 { 154 switch ($operationType) { 155 case static::OPERATION_GET: 156 return 'return $targetObject->$' . $nameParameter . ";"; 157 case static::OPERATION_SET: 158 if (! $valueParameter) { 159 throw new \InvalidArgumentException('Parameter $valueParameter not provided'); 160 } 161 162 return 'return $targetObject->$' . $nameParameter . ' = $' . $valueParameter . ';'; 163 case static::OPERATION_ISSET: 164 return 'return isset($targetObject->$' . $nameParameter . ');'; 165 case static::OPERATION_UNSET: 166 return 'unset($targetObject->$' . $nameParameter . ');'; 167 } 168 169 throw new \InvalidArgumentException(sprintf('Invalid operation "%s" provided', $operationType)); 170 } 171 172 /** 173 * Generates code to bind operations to the parent scope if supported by the current PHP implementation 174 * 175 * @return string 176 */ 177 private static function getScopeReBind() 178 { 179 if (! method_exists('Closure', 'bind')) { 180 // @codeCoverageIgnoreStart 181 return ''; 182 // @codeCoverageIgnoreEnd 183 } 184 185 return ' $backtrace = debug_backtrace(true);' . "\n" 186 . ' $scopeObject = isset($backtrace[1][\'object\'])' 187 . ' ? $backtrace[1][\'object\'] : new \stdClass();' . "\n" 188 . ' $accessor = $accessor->bindTo($scopeObject, get_class($scopeObject));' . "\n"; 189 } 190 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |