40
40
use function array_merge ;
41
41
use function func_get_arg ;
42
42
use function func_num_args ;
43
+ use function str_replace ;
44
+ use function substr ;
43
45
44
46
/**
45
47
* Generator for proxies implementing {@see \ProxyManager\Proxy\VirtualProxyInterface}
@@ -56,11 +58,11 @@ class LazyLoadingValueHolderGenerator implements ProxyGeneratorInterface
56
58
* @throws InvalidProxiedClassException
57
59
* @throws InvalidArgumentException
58
60
*
59
- * @psalm-param array{skipDestructor?: bool} $proxyOptions
61
+ * @psalm-param array{skipDestructor?: bool, fluentSafe?: bool } $proxyOptions
60
62
*/
61
63
public function generate (ReflectionClass $ originalClass , ClassGenerator $ classGenerator/*, array $proxyOptions = []*/ )
62
64
{
63
- /** @psalm-var array{skipDestructor?: bool} $proxyOptions */
65
+ /** @psalm-var array{skipDestructor?: bool, fluentSafe?: bool } $proxyOptions */
64
66
$ proxyOptions = func_num_args () >= 3 ? func_get_arg (2 ) : [];
65
67
66
68
CanProxyAssertion::assertClassCanBeProxied ($ originalClass );
@@ -92,7 +94,7 @@ static function (MethodGenerator $generatedMethod) use ($originalClass, $classGe
92
94
},
93
95
array_merge (
94
96
array_map (
95
- $ this ->buildLazyLoadingMethodInterceptor ($ initializer , $ valueHolder ),
97
+ $ this ->buildLazyLoadingMethodInterceptor ($ initializer , $ valueHolder, $ proxyOptions [ ' fluentSafe ' ] ?? false ),
96
98
ProxiedMethodsFilter::getProxiedMethods ($ originalClass , $ excludedMethods )
97
99
),
98
100
[
@@ -118,14 +120,33 @@ static function (MethodGenerator $generatedMethod) use ($originalClass, $classGe
118
120
119
121
private function buildLazyLoadingMethodInterceptor (
120
122
InitializerProperty $ initializer ,
121
- ValueHolderProperty $ valueHolder
123
+ ValueHolderProperty $ valueHolder ,
124
+ bool $ fluentSafe
122
125
): 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 (
125
129
new MethodReflection ($ method ->getDeclaringClass ()->getName (), $ method ->getName ()),
126
130
$ initializer ,
127
131
$ valueHolder
128
132
);
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 ;
129
150
};
130
151
}
131
152
}
0 commit comments