Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

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: 01.05.2026, 11:28 - Dateigröße: 6.57 KiB


 001  <?php
 002   
 003  declare(strict_types=1);
 004   
 005  namespace ProxyManager\ProxyGenerator\Util;
 006   
 007  use Zend\Code\Generator\PropertyGenerator;
 008   
 009  /**
 010   * Generates code necessary to simulate a fatal error in case of unauthorized
 011   * access to class members in magic methods even when in child classes and dealing
 012   * with protected members.
 013   *
 014   * @author Marco Pivetta <ocramius@gmail.com>
 015   * @license MIT
 016   */
 017  class PublicScopeSimulator
 018  {
 019      const OPERATION_SET   = 'set';
 020      const OPERATION_GET   = 'get';
 021      const OPERATION_ISSET = 'isset';
 022      const OPERATION_UNSET = 'unset';
 023   
 024      /**
 025       * Generates code for simulating access to a property from the scope that is accessing a proxy.
 026       * This is done by introspecting `debug_backtrace()` and then binding a closure to the scope
 027       * of the parent caller.
 028       *
 029       * @param string            $operationType      operation to execute: one of 'get', 'set', 'isset' or 'unset'
 030       * @param string            $nameParameter      name of the `name` parameter of the magic method
 031       * @param string|null       $valueParameter     name of the `value` parameter of the magic method
 032       * @param PropertyGenerator $valueHolder        name of the property containing the target object from which
 033       *                                              to read the property. `$this` if none provided
 034       * @param string|null       $returnPropertyName name of the property to which we want to assign the result of
 035       *                                              the operation. Return directly if none provided
 036       *
 037       * @throws \InvalidArgumentException
 038       */
 039      public static function getPublicAccessSimulationCode(
 040          string $operationType,
 041          string $nameParameter,
 042          $valueParameter = null,
 043          PropertyGenerator $valueHolder = null,
 044          $returnPropertyName = null
 045      ) : string {
 046          $byRef  = self::getByRefReturnValue($operationType);
 047          $value  = static::OPERATION_SET === $operationType ? ', $value' : '';
 048          $target = '$this';
 049   
 050          if ($valueHolder) {
 051              $target = '$this->' . $valueHolder->getName();
 052          }
 053   
 054          return '$realInstanceReflection = new \\ReflectionClass(get_parent_class($this));' . "\n\n"
 055              . 'if (! $realInstanceReflection->hasProperty($' . $nameParameter . ')) {'   . "\n"
 056              . '    $targetObject = ' . $target . ';' . "\n\n"
 057              . self::getUndefinedPropertyNotice($operationType, $nameParameter)
 058              . '    ' . self::getOperation($operationType, $nameParameter, $valueParameter) . "\n"
 059              . "    return;\n"
 060              . '}' . "\n\n"
 061              . '$targetObject = ' . self::getTargetObject($valueHolder) . ";\n"
 062              . '$accessor = function ' . $byRef . '() use ($targetObject, $name' . $value . ') {' . "\n"
 063              . '    ' . self::getOperation($operationType, $nameParameter, $valueParameter) . "\n"
 064              . "};\n"
 065              . self::getScopeReBind()
 066              . (
 067                  $returnPropertyName
 068                      ? '$' . $returnPropertyName . ' = ' . $byRef . '$accessor();'
 069                      : '$returnValue = ' . $byRef . '$accessor();' . "\n\n" . 'return $returnValue;'
 070              );
 071      }
 072   
 073      /**
 074       * This will generate code that triggers a notice if access is attempted on a non-existing property
 075       *
 076       * @param string $operationType
 077       * @param string $nameParameter
 078       *
 079       * @return string
 080       */
 081      private static function getUndefinedPropertyNotice(string $operationType, string $nameParameter) : string
 082      {
 083          if (static::OPERATION_GET !== $operationType) {
 084              return '';
 085          }
 086   
 087          return '    $backtrace = debug_backtrace(false);' . "\n"
 088              . '    trigger_error(' . "\n"
 089              . '        sprintf(' . "\n"
 090              . '            \'Undefined property: %s::$%s in %s on line %s\',' . "\n"
 091              . '            get_parent_class($this),' . "\n"
 092              . '            $' . $nameParameter . ',' . "\n"
 093              . '            $backtrace[0][\'file\'],' . "\n"
 094              . '            $backtrace[0][\'line\']' . "\n"
 095              . '        ),' . "\n"
 096              . '        \E_USER_NOTICE' . "\n"
 097              . '    );' . "\n";
 098      }
 099   
 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  }
 164