4040use function array_merge ;
4141use function func_get_arg ;
4242use function func_num_args ;
43+ use function str_replace ;
44+ use function substr ;
4345
4446/**
4547 * Generator for proxies implementing {@see \ProxyManager\Proxy\VirtualProxyInterface}
@@ -56,11 +58,11 @@ class LazyLoadingValueHolderGenerator implements ProxyGeneratorInterface
5658 * @throws InvalidProxiedClassException
5759 * @throws InvalidArgumentException
5860 *
59- * @psalm-param array{skipDestructor?: bool} $proxyOptions
61+ * @psalm-param array{skipDestructor?: bool, fluentSafe?: bool } $proxyOptions
6062 */
6163 public function generate (ReflectionClass $ originalClass , ClassGenerator $ classGenerator/*, array $proxyOptions = []*/ )
6264 {
63- /** @psalm-var array{skipDestructor?: bool} $proxyOptions */
65+ /** @psalm-var array{skipDestructor?: bool, fluentSafe?: bool } $proxyOptions */
6466 $ proxyOptions = func_num_args () >= 3 ? func_get_arg (2 ) : [];
6567
6668 CanProxyAssertion::assertClassCanBeProxied ($ originalClass );
@@ -92,7 +94,7 @@ static function (MethodGenerator $generatedMethod) use ($originalClass, $classGe
9294 },
9395 array_merge (
9496 array_map (
95- $ this ->buildLazyLoadingMethodInterceptor ($ initializer , $ valueHolder ),
97+ $ this ->buildLazyLoadingMethodInterceptor ($ initializer , $ valueHolder, $ proxyOptions [ ' fluentSafe ' ] ?? false ),
9698 ProxiedMethodsFilter::getProxiedMethods ($ originalClass , $ excludedMethods )
9799 ),
98100 [
@@ -118,14 +120,33 @@ static function (MethodGenerator $generatedMethod) use ($originalClass, $classGe
118120
119121 private function buildLazyLoadingMethodInterceptor (
120122 InitializerProperty $ initializer ,
121- ValueHolderProperty $ valueHolder
123+ ValueHolderProperty $ valueHolder ,
124+ bool $ fluentSafe
122125 ): callable {
123- return static function (ReflectionMethod $ method ) use ($ initializer , $ valueHolder ): LazyLoadingMethodInterceptor {
124- return LazyLoadingMethodInterceptor::generateMethod (
126+ return static function (ReflectionMethod $ method ) use ($ initializer , $ valueHolder , $ fluentSafe ): LazyLoadingMethodInterceptor {
127+ $ byRef = $ method ->returnsReference () ? '& ' : '' ;
128+ $ method = LazyLoadingMethodInterceptor::generateMethod (
125129 new MethodReflection ($ method ->getDeclaringClass ()->getName (), $ method ->getName ()),
126130 $ initializer ,
127131 $ valueHolder
128132 );
133+
134+ if ($ fluentSafe ) {
135+ $ valueHolderName = '$this-> ' . $ valueHolder ->getName ();
136+ $ body = $ method ->getBody ();
137+ $ newBody = str_replace ('return ' . $ valueHolderName , 'if ( ' . $ valueHolderName . ' === $returnValue = ' . $ byRef . $ valueHolderName , $ body );
138+
139+ if ($ newBody !== $ body ) {
140+ $ method ->setBody (
141+ substr ($ newBody , 0 , -1 ) . ') { ' . "\n"
142+ . ' return $this; ' . "\n"
143+ . '} ' . "\n\n"
144+ . 'return $returnValue; '
145+ );
146+ }
147+ }
148+
149+ return $ method ;
129150 };
130151 }
131152}
0 commit comments