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