= 3 ? func_get_arg(2) : []; 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($originalClass)); $classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty()); $classGenerator->addPropertyFromGenerator($publicProperties); $skipDestructor = ($proxyOptions['skipDestructor'] ?? false) && $originalClass->hasMethod('__destruct'); $excludedMethods = ProxiedMethodsFilter::DEFAULT_EXCLUDED; if ($skipDestructor) { $excludedMethods[] = '__destruct'; } array_map( static function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator): void { ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod); }, array_merge( array_map( $this->buildLazyLoadingMethodInterceptor($initializer, $valueHolder, $proxyOptions['fluentSafe'] ?? false), ProxiedMethodsFilter::getProxiedMethods($originalClass, $excludedMethods) ), [ 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), ], $skipDestructor ? [new SkipDestructor($initializer, $valueHolder)] : [] ) ); } private function buildLazyLoadingMethodInterceptor( InitializerProperty $initializer, ValueHolderProperty $valueHolder, bool $fluentSafe ): callable { return static function (ReflectionMethod $method) use ($initializer, $valueHolder, $fluentSafe): LazyLoadingMethodInterceptor { $byRef = $method->returnsReference() ? '& ' : ''; $method = LazyLoadingMethodInterceptor::generateMethod( new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()), $initializer, $valueHolder ); if ($fluentSafe) { $valueHolderName = '$this->' . $valueHolder->getName(); $body = $method->getBody(); $newBody = str_replace('return ' . $valueHolderName, 'if (' . $valueHolderName . ' === $returnValue = ' . $byRef . $valueHolderName, $body); if ($newBody !== $body) { $method->setBody( substr($newBody, 0, -1) . ') {' . "\n" . ' return $this;' . "\n" . '}' . "\n\n" . 'return $returnValue;' ); } } return $method; }; } }