Skip to content

Commit 7a3d612

Browse files
Merge branch '2.14.x' into 1.x
* 2.14.x: Corrected by-ref parameters also for scope-localizer interceptor proxies Converted #736 test case into an integration test Add access-interceptor-value-holder-intercepting-keeps-parameter-references.phpt Support reference params in interceptors Bump twig/twig from 2.14.6 to 2.14.11 revert final private Apply php 8.0 syntax Removed CHANGELOG.md
2 parents 7229414 + dbcdf2c commit 7a3d612

File tree

12 files changed

+296
-16
lines changed

12 files changed

+296
-16
lines changed

src/ProxyManager/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Util/InterceptorGenerator.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,13 @@ public static function createInterceptedMethodBody(
6767
'{{$suffixInterceptorsName}}' => $suffixInterceptors->getName(),
6868
'{{$suffixEarlyReturnExpression}}' => ProxiedMethodReturnExpression::generate('$suffixReturnValue', $originalMethod),
6969
'{{$returnExpression}}' => ProxiedMethodReturnExpression::generate('$returnValue', $originalMethod),
70-
'{{$paramsString}}' => 'array(' . implode(', ', array_map(static function (ParameterGenerator $parameter): string {
71-
return var_export($parameter->getName(), true) . ' => $' . $parameter->getName();
72-
}, $method->getParameters())) . ')',
70+
'{{$paramsString}}' => 'array(' . implode(', ', array_map(
71+
static function (ParameterGenerator $parameter): string {
72+
return var_export($parameter->getName(), true) . ' => ' . ($parameter->getPassedByReference() ? '&$' : '$') . $parameter->getName();
73+
},
74+
$method->getParameters()
75+
))
76+
. ')',
7377
];
7478

7579
return str_replace(

src/ProxyManager/ProxyGenerator/AccessInterceptorValueHolder/MethodGenerator/Util/InterceptorGenerator.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ public static function createInterceptedMethodBody(
6666

6767
foreach ($method->getParameters() as $parameter) {
6868
$parameterName = $parameter->getName();
69-
$params[] = var_export($parameterName, true) . ' => $' . $parameter->getName();
69+
$symbol = $parameter->getPassedByReference() ? '&$' : '$';
70+
$params[] = var_export($parameterName, true) . ' => ' . $symbol . $parameterName;
7071
}
7172

7273
$paramsString = 'array(' . implode(', ', $params) . ')';

tests/ProxyManagerTest/Factory/AbstractBaseFactoryTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ protected function setUp(): void
8686
$this
8787
->classNameInflector
8888
->method('getUserClassName')
89-
->willReturn('stdClass');
89+
->willReturn(stdClass::class);
9090

9191
$this->factory = $this->getMockForAbstractClass(AbstractBaseFactory::class, [$configuration]);
9292

@@ -103,7 +103,7 @@ public function testGeneratesClass(): void
103103
$this
104104
->classNameInflector
105105
->method('getProxyClassName')
106-
->with('stdClass')
106+
->with(stdClass::class)
107107
->willReturn($generatedClass);
108108

109109
$this

tests/ProxyManagerTest/Factory/AccessInterceptorScopeLocalizerFactoryTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public function testWillSkipAutoGeneration(): void
9494
->inflector
9595
->expects(self::once())
9696
->method('getProxyClassName')
97-
->with('stdClass')
97+
->with(stdClass::class)
9898
->willReturn(AccessInterceptorValueHolderMock::class);
9999

100100
$factory = new AccessInterceptorScopeLocalizerFactory($this->config);
@@ -164,14 +164,14 @@ static function (ClassGenerator $targetClass) use ($proxyClassName): bool {
164164
->inflector
165165
->expects(self::once())
166166
->method('getProxyClassName')
167-
->with('stdClass')
167+
->with(stdClass::class)
168168
->willReturn($proxyClassName);
169169

170170
$this
171171
->inflector
172172
->expects(self::once())
173173
->method('getUserClassName')
174-
->with('stdClass')
174+
->with(stdClass::class)
175175
->willReturn(LazyLoadingMock::class);
176176

177177
$this->signatureChecker->expects(self::atLeastOnce())->method('checkSignature');

tests/ProxyManagerTest/Factory/AccessInterceptorValueHolderFactoryTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function testWillSkipAutoGeneration(): void
9090
->inflector
9191
->expects(self::once())
9292
->method('getProxyClassName')
93-
->with('stdClass')
93+
->with(stdClass::class)
9494
->willReturn(AccessInterceptorValueHolderMock::class);
9595

9696
$factory = new AccessInterceptorValueHolderFactory($this->config);
@@ -159,14 +159,14 @@ static function (ClassGenerator $targetClass) use ($proxyClassName): bool {
159159
->inflector
160160
->expects(self::once())
161161
->method('getProxyClassName')
162-
->with('stdClass')
162+
->with(stdClass::class)
163163
->willReturn($proxyClassName);
164164

165165
$this
166166
->inflector
167167
->expects(self::once())
168168
->method('getUserClassName')
169-
->with('stdClass')
169+
->with(stdClass::class)
170170
->willReturn(EmptyClass::class);
171171

172172
$this->signatureChecker->expects(self::atLeastOnce())->method('checkSignature');

tests/ProxyManagerTest/Factory/NullObjectFactoryTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function testWillSkipAutoGeneration(): void
7575
->inflector
7676
->expects(self::once())
7777
->method('getProxyClassName')
78-
->with('stdClass')
78+
->with(stdClass::class)
7979
->willReturn(NullObjectMock::class);
8080

8181
(new NullObjectFactory($this->config))->createProxy($instance);
@@ -126,14 +126,14 @@ static function (ClassGenerator $targetClass) use ($proxyClassName): bool {
126126
->inflector
127127
->expects(self::once())
128128
->method('getProxyClassName')
129-
->with('stdClass')
129+
->with(stdClass::class)
130130
->willReturn($proxyClassName);
131131

132132
$this
133133
->inflector
134134
->expects(self::once())
135135
->method('getUserClassName')
136-
->with('stdClass')
136+
->with(stdClass::class)
137137
->willReturn(NullObjectMock::class);
138138

139139
$this->signatureChecker->expects(self::atLeastOnce())->method('checkSignature');

tests/ProxyManagerTest/Factory/RemoteObjectFactoryTest.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use ProxyManager\Signature\SignatureCheckerInterface;
1919
use ProxyManagerTestAsset\BaseInterface;
2020
use ProxyManagerTestAsset\RemoteProxy\RemoteObjectMock;
21+
use stdClass;
2122

2223
/**
2324
* @covers \ProxyManager\Factory\AbstractBaseFactory
@@ -130,7 +131,7 @@ static function (ClassGenerator $targetClass) use ($proxyClassName): bool {
130131
->expects(self::once())
131132
->method('getUserClassName')
132133
->with(BaseInterface::class)
133-
->willReturn('stdClass');
134+
->willReturn(stdClass::class);
134135

135136
$this->signatureChecker->expects(self::atLeastOnce())->method('checkSignature');
136137
$this->classSignatureGenerator->expects(self::once())->method('addSignature')->will(self::returnArgument(0));

tests/ProxyManagerTest/Functional/AccessInterceptorScopeLocalizerFunctionalTest.php

+74
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use ProxyManagerTestAsset\ClassWithPublicStringNullableTypedProperty;
2525
use ProxyManagerTestAsset\ClassWithSelfHint;
2626
use ProxyManagerTestAsset\EmptyClass;
27+
use ProxyManagerTestAsset\ReferenceIncrementDecrementClass;
2728
use ProxyManagerTestAsset\VoidCounter;
2829
use ReflectionClass;
2930
use stdClass;
@@ -575,6 +576,79 @@ public function testWillRefuseToGenerateReferencesToTypedPropertiesWithoutDefaul
575576
$factory->createProxy($instance);
576577
}
577578

579+
public function testByReferencePassedArgumentsAreGivenAsReferenceToInterceptorCallbacks(): void
580+
{
581+
$proxy = (new AccessInterceptorScopeLocalizerFactory())->createProxy(
582+
new ReferenceIncrementDecrementClass(),
583+
[
584+
'incrementReference' => static function (
585+
$proxy,
586+
ReferenceIncrementDecrementClass $instance,
587+
string $method,
588+
array $args,
589+
bool &$returnEarly
590+
): void {
591+
self::assertSame(0, $args['reference']);
592+
593+
$returnEarly = true;
594+
$args['reference'] = 5;
595+
},
596+
]
597+
);
598+
599+
$number = 0;
600+
601+
$proxy->incrementReference($number);
602+
603+
self::assertSame(5, $number, 'Number was changed by interceptor');
604+
}
605+
606+
public function testByReferenceArgumentsAreForwardedThroughInterceptorsAndSubject(): void
607+
{
608+
$proxy = (new AccessInterceptorScopeLocalizerFactory())->createProxy(
609+
new ReferenceIncrementDecrementClass(),
610+
[
611+
'incrementReference' => static function (
612+
$proxy,
613+
ReferenceIncrementDecrementClass $instance,
614+
string $method,
615+
array $args,
616+
bool &$returnEarly
617+
): void {
618+
self::assertSame(0, $args['reference']);
619+
620+
$returnEarly = false;
621+
$args['reference'] = 5;
622+
},
623+
],
624+
[
625+
'incrementReference' => static function (
626+
$proxy,
627+
ReferenceIncrementDecrementClass $instance,
628+
string $method,
629+
array $args,
630+
$returnValue,
631+
bool &$returnEarly
632+
): void {
633+
self::assertIsInt($args['reference']);
634+
635+
$returnEarly = false;
636+
$args['reference'] *= 2;
637+
},
638+
]
639+
);
640+
641+
$number = 0;
642+
643+
$proxy->incrementReference($number);
644+
645+
self::assertSame(
646+
12,
647+
$number,
648+
'Number was changed by prefix interceptor, then incremented, then doubled by suffix interceptor'
649+
);
650+
}
651+
578652
/**
579653
* @psalm-param ExpectedType $expected
580654
*

tests/ProxyManagerTest/Functional/AccessInterceptorValueHolderFunctionalTest.php

+74
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use ProxyManagerTestAsset\ClassWithSelfHint;
2626
use ProxyManagerTestAsset\EmptyClass;
2727
use ProxyManagerTestAsset\OtherObjectAccessClass;
28+
use ProxyManagerTestAsset\ReferenceIncrementDecrementClass;
2829
use ProxyManagerTestAsset\VoidCounter;
2930
use ReflectionClass;
3031
use ReflectionProperty;
@@ -711,6 +712,79 @@ public function testWillInterceptAndReturnEarlyOnVoidMethod(): void
711712
self::assertSame($increment + $addMore + 1, $object->counter);
712713
}
713714

715+
public function testByReferencePassedArgumentsAreGivenAsReferenceToInterceptorCallbacks(): void
716+
{
717+
$proxy = (new AccessInterceptorValueHolderFactory())->createProxy(
718+
new ReferenceIncrementDecrementClass(),
719+
[
720+
'incrementReference' => static function (
721+
$proxy,
722+
ReferenceIncrementDecrementClass $instance,
723+
string $method,
724+
array $args,
725+
bool &$returnEarly
726+
): void {
727+
self::assertSame(0, $args['reference']);
728+
729+
$returnEarly = true;
730+
$args['reference'] = 5;
731+
},
732+
]
733+
);
734+
735+
$number = 0;
736+
737+
$proxy->incrementReference($number);
738+
739+
self::assertSame(5, $number, 'Number was changed by interceptor');
740+
}
741+
742+
public function testByReferenceArgumentsAreForwardedThroughInterceptorsAndSubject(): void
743+
{
744+
$proxy = (new AccessInterceptorValueHolderFactory())->createProxy(
745+
new ReferenceIncrementDecrementClass(),
746+
[
747+
'incrementReference' => static function (
748+
$proxy,
749+
ReferenceIncrementDecrementClass $instance,
750+
string $method,
751+
array $args,
752+
bool &$returnEarly
753+
): void {
754+
self::assertSame(0, $args['reference']);
755+
756+
$returnEarly = false;
757+
$args['reference'] = 5;
758+
},
759+
],
760+
[
761+
'incrementReference' => static function (
762+
$proxy,
763+
ReferenceIncrementDecrementClass $instance,
764+
string $method,
765+
array $args,
766+
$returnValue,
767+
bool &$returnEarly
768+
): void {
769+
self::assertIsInt($args['reference']);
770+
771+
$returnEarly = false;
772+
$args['reference'] *= 2;
773+
},
774+
]
775+
);
776+
777+
$number = 0;
778+
779+
$proxy->incrementReference($number);
780+
781+
self::assertSame(
782+
12,
783+
$number,
784+
'Number was changed by prefix interceptor, then incremented, then doubled by suffix interceptor'
785+
);
786+
}
787+
714788
private static function assertByRefVariableValueSame($expected, & $actual): void
715789
{
716790
self::assertSame($expected, $actual);

tests/ProxyManagerTest/ProxyGenerator/AccessInterceptorScopeLocalizer/MethodGenerator/Util/InterceptorGeneratorTest.php

+55
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,61 @@ public function testInterceptorGeneratorWithExistingNonVoidMethod(): void
167167
}
168168
}
169169
170+
return $returnValue;
171+
PHP;
172+
// @codingStandardsIgnoreEnd
173+
174+
self::assertSame(
175+
$expected,
176+
InterceptorGenerator::createInterceptedMethodBody(
177+
'$returnValue = "foo";',
178+
$method,
179+
$prefixInterceptors,
180+
$suffixInterceptors,
181+
new ReflectionMethod(BaseClass::class, 'publicMethod')
182+
)
183+
);
184+
}
185+
186+
public function testInterceptorGeneratorWithReferences(): void
187+
{
188+
$method = $this->createMock(MethodGenerator::class);
189+
$bar = $this->createMock(ParameterGenerator::class);
190+
$baz = $this->createMock(ParameterGenerator::class);
191+
$prefixInterceptors = $this->createMock(PropertyGenerator::class);
192+
$suffixInterceptors = $this->createMock(PropertyGenerator::class);
193+
194+
$bar->method('getName')->willReturn('bar');
195+
$bar->method('getPassedByReference')->willReturn(false);
196+
$baz->method('getName')->willReturn('baz');
197+
$baz->method('getPassedByReference')->willReturn(true);
198+
$method->method('getName')->willReturn('fooMethod');
199+
$method->method('getParameters')->will(self::returnValue([$bar, $baz]));
200+
$prefixInterceptors->method('getName')->willReturn('pre');
201+
$suffixInterceptors->method('getName')->willReturn('post');
202+
203+
// @codingStandardsIgnoreStart
204+
$expected = <<<'PHP'
205+
if (isset($this->pre['fooMethod'])) {
206+
$returnEarly = false;
207+
$prefixReturnValue = $this->pre['fooMethod']->__invoke($this, $this, 'fooMethod', array('bar' => $bar, 'baz' => &$baz), $returnEarly);
208+
209+
if ($returnEarly) {
210+
return $prefixReturnValue;
211+
}
212+
}
213+
214+
$returnValue = "foo";
215+
216+
if (isset($this->post['fooMethod'])) {
217+
$returnEarly = false;
218+
$suffixReturnValue = $this->post['fooMethod']->__invoke($this, $this, 'fooMethod', array('bar' => $bar, 'baz' => &$baz), $returnValue, $returnEarly);
219+
220+
if ($returnEarly) {
221+
return $suffixReturnValue;
222+
}
223+
}
224+
170225
return $returnValue;
171226
PHP;
172227
// @codingStandardsIgnoreEnd

0 commit comments

Comments
 (0)