Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
PublicScopeSimulator.php
001 <?php
002 /*
003 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
004 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
005 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
006 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
007 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
008 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
009 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
010 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
011 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
012 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
013 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
014 *
015 * This software consists of voluntary contributions made by many individuals
016 * and is licensed under the MIT license.
017 */
018
019 namespace ProxyManager\ProxyGenerator\Util;
020
021 use Zend\Code\Generator\PropertyGenerator;
022
023 /**
024 * Generates code necessary to simulate a fatal error in case of unauthorized
025 * access to class members in magic methods even when in child classes and dealing
026 * with protected members.
027 *
028 * @author Marco Pivetta <ocramius@gmail.com>
029 * @license MIT
030 */
031 class PublicScopeSimulator
032 {
033 const OPERATION_SET = 'set';
034 const OPERATION_GET = 'get';
035 const OPERATION_ISSET = 'isset';
036 const OPERATION_UNSET = 'unset';
037
038 /**
039 * Generates code for simulating access to a property from the scope that is accessing a proxy.
040 * This is done by introspecting `debug_backtrace()` and then binding a closure to the scope
041 * of the parent caller.
042 *
043 * @param string $operationType operation to execute: one of 'get', 'set', 'isset' or 'unset'
044 * @param string $nameParameter name of the `name` parameter of the magic method
045 * @param string|null $valueParameter name of the `value` parameter of the magic method
046 * @param PropertyGenerator $valueHolder name of the property containing the target object from which
047 * to read the property. `$this` if none provided
048 * @param string|null $returnPropertyName name of the property to which we want to assign the result of
049 * the operation. Return directly if none provided
050 *
051 * @return string
052 *
053 * @throws \InvalidArgumentException
054 */
055 public static function getPublicAccessSimulationCode(
056 $operationType,
057 $nameParameter,
058 $valueParameter = null,
059 PropertyGenerator $valueHolder = null,
060 $returnPropertyName = null
061 ) {
062 $byRef = self::getByRefReturnValue($operationType);
063 $value = static::OPERATION_SET === $operationType ? ', $value' : '';
064 $target = '$this';
065
066 if ($valueHolder) {
067 $target = '$this->' . $valueHolder->getName();
068 }
069
070 return '$realInstanceReflection = new \\ReflectionClass(get_parent_class($this));' . "\n\n"
071 . 'if (! $realInstanceReflection->hasProperty($' . $nameParameter . ')) {' . "\n"
072 . ' $targetObject = ' . $target . ';' . "\n\n"
073 . self::getUndefinedPropertyNotice($operationType, $nameParameter)
074 . ' ' . self::getOperation($operationType, $nameParameter, $valueParameter) . ";\n"
075 . " return;\n"
076 . '}' . "\n\n"
077 . '$targetObject = ' . self::getTargetObject($valueHolder) . ";\n"
078 . '$accessor = function ' . $byRef . '() use ($targetObject, $name' . $value . ') {' . "\n"
079 . ' ' . self::getOperation($operationType, $nameParameter, $valueParameter) . "\n"
080 . "};\n"
081 . self::getScopeReBind()
082 . (
083 $returnPropertyName
084 ? '$' . $returnPropertyName . ' = ' . $byRef . '$accessor();'
085 : '$returnValue = ' . $byRef . '$accessor();' . "\n\n" . 'return $returnValue;'
086 );
087 }
088
089 /**
090 * This will generate code that triggers a notice if access is attempted on a non-existing property
091 *
092 * @param string $operationType
093 * @param string $nameParameter
094 *
095 * @return string
096 */
097 private static function getUndefinedPropertyNotice($operationType, $nameParameter)
098 {
099 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 }
191