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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

PublicScopeSimulator.php

Zuletzt modifiziert: 09.10.2024, 12:59 - Dateigröße: 7.54 KiB


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