/** * * @param Properties $properties * * @return int[][]|mixed[][] */ private function getMap(Properties $properties) { $map = []; foreach ($properties->getProtectedProperties() as $property) { $map[$property->getName()] = $property->getDeclaringClass()->getName(); } return $map; }
/** * @param Properties $properties * * @return int[][]|mixed[][] */ private function getMap(Properties $properties) : array { $map = []; foreach ($properties->getPrivateProperties() as $property) { $propertyKey =& $map[$property->getName()]; $propertyKey[$property->getDeclaringClass()->getName()] = true; } return $map; }
/** * @param Properties $properties */ public function __construct(Properties $properties) { parent::__construct(UniqueIdentifierGenerator::getIdentifier('publicProperties')); foreach ($properties->getPublicProperties() as $publicProperty) { $this->publicProperties[$publicProperty->getName()] = true; } $this->setDefaultValue($this->publicProperties); $this->setVisibility(self::VISIBILITY_PRIVATE); $this->setStatic(true); $this->setDocblock('@var bool[] map of public properties of the parent class'); }
/** * @param Properties $properties * * @return string */ private function generateUnsetPropertiesCode(Properties $properties) { $code = ''; if ($accessibleProperties = $properties->getAccessibleProperties()) { $code .= $this->getUnsetPropertiesGroupCode($accessibleProperties) . "\n"; } foreach ($properties->getGroupedPrivateProperties() as $className => $privateProperties) { $cacheKey = 'cache' . str_replace('\\', '_', $className); $code .= 'static $' . $cacheKey . ";\n\n" . '$' . $cacheKey . ' ?: $' . $cacheKey . " = \\Closure::bind(function (\$instance) {\n" . ' ' . $this->getUnsetPropertiesGroupCode($privateProperties) . '}, null, ' . var_export($className, true) . ");\n\n" . '$' . $cacheKey . "(\$instance);\n\n"; } return $code; }
/** * Constructor * * @param ReflectionClass $originalClass Reflection of the class to proxy * @param PropertyGenerator $adapter Adapter property */ public function __construct(ReflectionClass $originalClass, PropertyGenerator $adapter) { $adapterName = $adapter->getName(); parent::__construct('staticProxyConstructor', [new ParameterGenerator($adapterName, AdapterInterface::class)], MethodGenerator::FLAG_PUBLIC | MethodGenerator::FLAG_STATIC, null, 'Constructor for remote object control\\n\\n' . '@param \\ProxyManager\\Factory\\RemoteObject\\AdapterInterface \\$adapter'); $body = 'static $reflection;' . "\n\n" . '$reflection = $reflection ?: $reflection = new \\ReflectionClass(__CLASS__);' . "\n" . '$instance = (new \\ReflectionClass(get_class()))->newInstanceWithoutConstructor();' . "\n\n" . '$instance->' . $adapterName . ' = $' . $adapterName . ";\n\n" . UnsetPropertiesGenerator::generateSnippet(Properties::fromReflectionClass($originalClass), 'instance'); $this->setBody($body . "\n\nreturn \$instance;"); }
/** * @param ReflectionClass $class * * @return string */ private static function getUnsetPropertiesString(ReflectionClass $class) { $unsetProperties = implode("\n ", array_map(function (ReflectionProperty $unsetProperty) { return 'unset($this->' . $unsetProperty->getName() . ');'; }, Properties::fromReflectionClass($class)->getPublicProperties())); return $unsetProperties ? "\n " . $unsetProperties . "\n" : ''; }
/** * Constructor * * @param ReflectionClass $originalClass */ public function __construct(ReflectionClass $originalClass) { parent::__construct($originalClass, '__wakeup'); $unsetProperties = array_map(function (ReflectionProperty $property) { return '$this->' . $property->getName(); }, Properties::fromReflectionClass($originalClass)->getPublicProperties()); $this->setBody($unsetProperties ? 'unset(' . implode(', ', $unsetProperties) . ");" : ''); }
/** * Constructor * * @param ReflectionClass $originalClass * @param PropertyGenerator $valueHolder * * @return self */ public static function generateMethod(ReflectionClass $originalClass, PropertyGenerator $valueHolder) : self { $originalConstructor = self::getConstructor($originalClass); $constructor = $originalConstructor ? self::fromReflection($originalConstructor) : new self('__construct'); $constructor->setDocblock('{@inheritDoc}'); $constructor->setBody('static $reflection;' . "\n\n" . 'if (! $this->' . $valueHolder->getName() . ') {' . "\n" . ' $reflection = $reflection ?: new \\ReflectionClass(' . var_export($originalClass->getName(), true) . ");\n" . ' $this->' . $valueHolder->getName() . ' = $reflection->newInstanceWithoutConstructor();' . "\n" . UnsetPropertiesGenerator::generateSnippet(Properties::fromReflectionClass($originalClass), 'this') . "}" . self::generateOriginalConstructorCall($originalClass, $valueHolder)); return $constructor; }
/** * Constructor * * @param ReflectionClass $originalClass Reflection of the class to proxy */ public function __construct(ReflectionClass $originalClass) { parent::__construct('staticProxyConstructor', [], static::FLAG_PUBLIC | static::FLAG_STATIC); $nullableProperties = array_map(function (ReflectionProperty $publicProperty) { return '$instance->' . $publicProperty->getName() . ' = null;'; }, Properties::fromReflectionClass($originalClass)->getPublicProperties()); $this->setDocblock("Constructor for null object initialization"); $this->setBody('static $reflection;' . "\n\n" . '$reflection = $reflection ?: $reflection = new \\ReflectionClass(__CLASS__);' . "\n" . '$instance = (new \\ReflectionClass(get_class()))->newInstanceWithoutConstructor();' . "\n\n" . ($nullableProperties ? implode("\n", $nullableProperties) . "\n\n" : '') . 'return $instance;'); }
/** * Constructor * * @param ReflectionClass $originalClass * @param PropertyGenerator $prefixInterceptors * @param PropertyGenerator $suffixInterceptors */ public function __construct(ReflectionClass $originalClass, PropertyGenerator $prefixInterceptors, PropertyGenerator $suffixInterceptors) { parent::__construct('bindProxyProperties', [new ParameterGenerator('localizedObject', $originalClass->getName()), new ParameterGenerator('prefixInterceptors', 'array', []), new ParameterGenerator('suffixInterceptors', 'array', [])], static::FLAG_PRIVATE, null, "@override constructor to setup interceptors\n\n" . "@param \\" . $originalClass->getName() . " \$localizedObject\n" . "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n" . "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic"); $localizedProperties = []; $properties = Properties::fromReflectionClass($originalClass); foreach ($properties->getAccessibleProperties() as $property) { $propertyName = $property->getName(); $localizedProperties[] = '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";"; } foreach ($properties->getPrivateProperties() as $property) { $propertyName = $property->getName(); $localizedProperties[] = "\\Closure::bind(function () use (\$localizedObject) {\n " . '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";\n" . '}, $this, ' . var_export($property->getDeclaringClass()->getName(), true) . ')->__invoke();'; } $this->setBody((empty($localizedProperties) ? '' : implode("\n\n", $localizedProperties) . "\n\n") . '$this->' . $prefixInterceptors->getName() . " = \$prefixInterceptors;\n" . '$this->' . $suffixInterceptors->getName() . " = \$suffixInterceptors;"); }
/** * Constructor * * @param ReflectionClass $originalClass * @param PropertyGenerator $valueHolder * @param PropertyGenerator $prefixInterceptors * @param PropertyGenerator $suffixInterceptors */ public function __construct(ReflectionClass $originalClass, PropertyGenerator $valueHolder, PropertyGenerator $prefixInterceptors, PropertyGenerator $suffixInterceptors) { parent::__construct('staticProxyConstructor', [], static::FLAG_PUBLIC | static::FLAG_STATIC); $prefix = new ParameterGenerator('prefixInterceptors'); $suffix = new ParameterGenerator('suffixInterceptors'); $prefix->setDefaultValue([]); $suffix->setDefaultValue([]); $prefix->setType('array'); $suffix->setType('array'); $this->setParameter(new ParameterGenerator('wrappedObject')); $this->setParameter($prefix); $this->setParameter($suffix); $this->setReturnType($originalClass->getName()); $this->setDocblock("Constructor to setup interceptors\n\n" . "@param \\" . $originalClass->getName() . " \$wrappedObject\n" . "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n" . "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic\n\n" . "@return self"); $this->setBody('static $reflection;' . "\n\n" . '$reflection = $reflection ?: $reflection = new \\ReflectionClass(__CLASS__);' . "\n" . '$instance = (new \\ReflectionClass(get_class()))->newInstanceWithoutConstructor();' . "\n\n" . UnsetPropertiesGenerator::generateSnippet(Properties::fromReflectionClass($originalClass), 'instance') . '$instance->' . $valueHolder->getName() . " = \$wrappedObject;\n" . '$instance->' . $prefixInterceptors->getName() . " = \$prefixInterceptors;\n" . '$instance->' . $suffixInterceptors->getName() . " = \$suffixInterceptors;\n\n" . 'return $instance;'); }
/** * {@inheritDoc} */ public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator) { CanProxyAssertion::assertClassCanBeProxied($originalClass); $interfaces = [VirtualProxyInterface::class]; $publicProperties = new PublicPropertiesMap(Properties::fromReflectionClass($originalClass)); if ($originalClass->isInterface()) { $interfaces[] = $originalClass->getName(); } else { $classGenerator->setExtendedClass($originalClass->getName()); } $classGenerator->setImplementedInterfaces($interfaces); $classGenerator->addPropertyFromGenerator($valueHolder = new ValueHolderProperty()); $classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty()); $classGenerator->addPropertyFromGenerator($publicProperties); array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) { ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod); }, array_merge(array_map($this->buildLazyLoadingMethodInterceptor($initializer, $valueHolder), ProxiedMethodsFilter::getProxiedMethods($originalClass)), [new StaticProxyConstructor($initializer, Properties::fromReflectionClass($originalClass)), Constructor::generateMethod($originalClass, $valueHolder), new MagicGet($originalClass, $initializer, $valueHolder, $publicProperties), new MagicSet($originalClass, $initializer, $valueHolder, $publicProperties), new MagicIsset($originalClass, $initializer, $valueHolder, $publicProperties), new MagicUnset($originalClass, $initializer, $valueHolder, $publicProperties), new MagicClone($originalClass, $initializer, $valueHolder), new MagicSleep($originalClass, $initializer, $valueHolder), new MagicWakeup($originalClass), new SetProxyInitializer($initializer), new GetProxyInitializer($initializer), new InitializeProxy($initializer, $valueHolder), new IsProxyInitialized($valueHolder), new GetWrappedValueHolderValue($valueHolder)])); }
/** * {@inheritDoc} */ public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator, array $proxyOptions = []) { CanProxyAssertion::assertClassCanBeProxied($originalClass, false); $filteredProperties = Properties::fromReflectionClass($originalClass)->filter(isset($proxyOptions['skippedProperties']) ? $proxyOptions['skippedProperties'] : []); $publicProperties = new PublicPropertiesMap($filteredProperties); $privateProperties = new PrivatePropertiesMap($filteredProperties); $protectedProperties = new ProtectedPropertiesMap($filteredProperties); $classGenerator->setExtendedClass($originalClass->getName()); $classGenerator->setImplementedInterfaces([GhostObjectInterface::class]); $classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty()); $classGenerator->addPropertyFromGenerator($initializationTracker = new InitializationTracker()); $classGenerator->addPropertyFromGenerator($publicProperties); $classGenerator->addPropertyFromGenerator($privateProperties); $classGenerator->addPropertyFromGenerator($protectedProperties); $init = new CallInitializer($initializer, $initializationTracker, $filteredProperties); array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) { ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod); }, array_merge($this->getAbstractProxiedMethods($originalClass), [$init, new StaticProxyConstructor($initializer, $filteredProperties), new MagicGet($originalClass, $initializer, $init, $publicProperties, $protectedProperties, $privateProperties, $initializationTracker), new MagicSet($originalClass, $initializer, $init, $publicProperties, $protectedProperties, $privateProperties), new MagicIsset($originalClass, $initializer, $init, $publicProperties, $protectedProperties, $privateProperties), new MagicUnset($originalClass, $initializer, $init, $publicProperties, $protectedProperties, $privateProperties), new MagicClone($originalClass, $initializer, $init, $publicProperties), new MagicSleep($originalClass, $initializer, $init, $publicProperties), new SetProxyInitializer($initializer), new GetProxyInitializer($initializer), new InitializeProxy($initializer, $init), new IsProxyInitialized($initializer)])); }
/** * {@inheritDoc} */ public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator) { CanProxyAssertion::assertClassCanBeProxied($originalClass); $publicProperties = new PublicPropertiesMap(Properties::fromReflectionClass($originalClass)); $interfaces = [AccessInterceptorInterface::class, ValueHolderInterface::class]; if ($originalClass->isInterface()) { $interfaces[] = $originalClass->getName(); } else { $classGenerator->setExtendedClass($originalClass->getName()); } $classGenerator->setImplementedInterfaces($interfaces); $classGenerator->addPropertyFromGenerator($valueHolder = new ValueHolderProperty()); $classGenerator->addPropertyFromGenerator($prefixInterceptors = new MethodPrefixInterceptors()); $classGenerator->addPropertyFromGenerator($suffixInterceptors = new MethodSuffixInterceptors()); $classGenerator->addPropertyFromGenerator($publicProperties); array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) { ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod); }, array_merge(array_map(function (ReflectionMethod $method) use($prefixInterceptors, $suffixInterceptors, $valueHolder) { return InterceptedMethod::generateMethod(new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()), $valueHolder, $prefixInterceptors, $suffixInterceptors); }, ProxiedMethodsFilter::getProxiedMethods($originalClass)), [Constructor::generateMethod($originalClass, $valueHolder), new StaticProxyConstructor($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors), new GetWrappedValueHolderValue($valueHolder), new SetMethodPrefixInterceptor($prefixInterceptors), new SetMethodSuffixInterceptor($suffixInterceptors), new MagicGet($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors, $publicProperties), new MagicSet($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors, $publicProperties), new MagicIsset($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors, $publicProperties), new MagicUnset($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors, $publicProperties), new MagicClone($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors), new MagicSleep($originalClass, $valueHolder), new MagicWakeup($originalClass, $valueHolder)])); }
/** * @param Properties $properties * * @return string */ private function propertiesReferenceArrayCode(Properties $properties) { $assignments = []; foreach ($properties->getAccessibleProperties() as $propertyInternalName => $property) { $assignments[] = ' ' . var_export($propertyInternalName, true) . ' => & $this->' . $property->getName() . ','; } $code = "\$properties = [\n" . implode("\n", $assignments) . "\n];\n\n"; // must use assignments, as direct reference during array definition causes a fatal error (not sure why) foreach ($properties->getGroupedPrivateProperties() as $className => $classPrivateProperties) { $cacheKey = 'cacheFetch' . str_replace('\\', '_', $className); $code .= 'static $' . $cacheKey . ";\n\n" . '$' . $cacheKey . ' ?: $' . $cacheKey . " = \\Closure::bind(function (\$instance, array & \$properties) {\n" . $this->generatePrivatePropertiesAssignmentsCode($classPrivateProperties) . "}, \$this, " . var_export($className, true) . ");\n\n" . '$' . $cacheKey . "(\$this, \$properties);"; } return $code; }
/** * Constructor * * @param ReflectionClass $originalClass */ public function __construct(ReflectionClass $originalClass) { parent::__construct($originalClass, '__wakeup'); $this->setBody(UnsetPropertiesGenerator::generateSnippet(Properties::fromReflectionClass($originalClass), 'this')); }