Skip to content

Commit 1cb7161

Browse files
Abstract methods should not be rewritten by proxies (#5268)
Co-authored-by: 李铭昕 <[email protected]>
1 parent 7f1a22e commit 1cb7161

File tree

6 files changed

+214
-1
lines changed

6 files changed

+214
-1
lines changed

src/Aop/ProxyCallVisitor.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ private function getMagicConst(): Node\Scalar\MagicConst
210210

211211
private function shouldRewrite(ClassMethod $node): bool
212212
{
213-
if ($this->visitorMetadata->classLike == Node\Stmt\Interface_::class) {
213+
if ($this->visitorMetadata->classLike == Node\Stmt\Interface_::class || $node->isAbstract()) {
214214
return false;
215215
}
216216

tests/Aop/ProxyCallVisitorTest.php

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace HyperfTest\Di\Aop;
13+
14+
use Hyperf\Di\Aop\Ast;
15+
use Hyperf\Di\Aop\ProxyCallVisitor;
16+
use Hyperf\Di\Aop\VisitorMetadata;
17+
use HyperfTest\Di\Stub\AspectCollector;
18+
use PhpParser\Node;
19+
use PhpParser\Node\Stmt\ClassMethod;
20+
use PHPUnit\Framework\TestCase;
21+
use ReflectionMethod;
22+
23+
/**
24+
* @internal
25+
* @coversNothing
26+
*/
27+
class ProxyCallVisitorTest extends TestCase
28+
{
29+
protected function tearDown(): void
30+
{
31+
AspectCollector::clear();
32+
}
33+
34+
public function testShouldRewrite()
35+
{
36+
$code = <<<'CODETEMPLATE'
37+
<?php
38+
abstract class SomeClass
39+
{
40+
abstract protected function foo();
41+
42+
protected function bar()
43+
{
44+
}
45+
}
46+
CODETEMPLATE;
47+
48+
$ast = new Ast();
49+
$stmts = $ast->parse($code)[0];
50+
51+
$aspect = 'App\Aspect\DebugAspect';
52+
AspectCollector::setAround($aspect, [
53+
'SomeClass',
54+
], []);
55+
56+
$proxyCallVisitor = new ProxyCallVisitor(new VisitorMetadata('SomeClass'));
57+
58+
$reflectionMethod = new ReflectionMethod($proxyCallVisitor, 'shouldRewrite');
59+
$reflectionMethod->setAccessible(true);
60+
$this->assertFalse($reflectionMethod->invoke($proxyCallVisitor, $stmts->stmts[0]));
61+
$this->assertTrue($reflectionMethod->invoke($proxyCallVisitor, $stmts->stmts[1]));
62+
}
63+
64+
public function testInterfaceShouldNotRewrite()
65+
{
66+
$aspect = 'App\Aspect\DebugAspect';
67+
AspectCollector::setAround($aspect, [
68+
'SomeClass',
69+
], []);
70+
71+
$visitorMetadata = new VisitorMetadata('SomeClass');
72+
$proxyCallVisitor = new ProxyCallVisitor($visitorMetadata);
73+
74+
$reflectionMethod = new ReflectionMethod($proxyCallVisitor, 'shouldRewrite');
75+
$reflectionMethod->setAccessible(true);
76+
$this->assertTrue($reflectionMethod->invoke($proxyCallVisitor, new ClassMethod('foo')));
77+
78+
$visitorMetadata->classLike = Node\Stmt\Interface_::class;
79+
$this->assertFalse($reflectionMethod->invoke($proxyCallVisitor, new ClassMethod('foo')));
80+
}
81+
}

tests/AstTest.php

+62
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@
1414
use Hyperf\Di\Aop\Ast;
1515
use Hyperf\Di\ReflectionManager;
1616
use HyperfTest\Di\Stub\AspectCollector;
17+
use HyperfTest\Di\Stub\Ast\Abs;
18+
use HyperfTest\Di\Stub\Ast\AbsAspect;
1719
use HyperfTest\Di\Stub\Ast\Bar2;
1820
use HyperfTest\Di\Stub\Ast\Bar3;
1921
use HyperfTest\Di\Stub\Ast\Bar4;
2022
use HyperfTest\Di\Stub\Ast\Bar5;
2123
use HyperfTest\Di\Stub\Ast\BarAspect;
2224
use HyperfTest\Di\Stub\Ast\BarInterface;
25+
use HyperfTest\Di\Stub\Ast\Chi;
2326
use HyperfTest\Di\Stub\Ast\Foo;
2427
use HyperfTest\Di\Stub\Ast\FooTrait;
2528
use HyperfTest\Di\Stub\FooEnumStruct;
@@ -113,6 +116,65 @@ public function __construct(public FooEnum $enum = FooEnum::DEFAULT)
113116
}', $code);
114117
}
115118

119+
public function testAbstractMethod()
120+
{
121+
$aspect = AbsAspect::class;
122+
AspectCollector::setAround($aspect, [
123+
Chi::class,
124+
Abs::class,
125+
], []);
126+
127+
$ast = new Ast();
128+
$code = $ast->proxy(Abs::class);
129+
130+
$this->assertSame($this->license . "
131+
namespace HyperfTest\\Di\\Stub\\Ast;
132+
133+
abstract class Abs
134+
{
135+
use \\Hyperf\\Di\\Aop\\ProxyTrait;
136+
use \\Hyperf\\Di\\Aop\\PropertyHandlerTrait;
137+
function __construct()
138+
{
139+
\$this->__handlePropertyHandler(__CLASS__);
140+
}
141+
public function abs() : string
142+
{
143+
\$__function__ = __FUNCTION__;
144+
\$__method__ = __METHOD__;
145+
return self::__proxyCall(__CLASS__, __FUNCTION__, self::__getParamsMap(__CLASS__, __FUNCTION__, func_get_args()), function () use(\$__function__, \$__method__) {
146+
return 'abs';
147+
});
148+
}
149+
public abstract function absabs() : string;
150+
}", $code);
151+
152+
$code = $ast->proxy(Chi::class);
153+
$this->assertSame($this->license . '
154+
namespace HyperfTest\Di\Stub\Ast;
155+
156+
class Chi extends Abs
157+
{
158+
use \Hyperf\Di\Aop\ProxyTrait;
159+
use \Hyperf\Di\Aop\PropertyHandlerTrait;
160+
function __construct()
161+
{
162+
if (method_exists(parent::class, \'__construct\')) {
163+
parent::__construct(...func_get_args());
164+
}
165+
$this->__handlePropertyHandler(__CLASS__);
166+
}
167+
public function absabs() : string
168+
{
169+
$__function__ = __FUNCTION__;
170+
$__method__ = __METHOD__;
171+
return self::__proxyCall(__CLASS__, __FUNCTION__, self::__getParamsMap(__CLASS__, __FUNCTION__, func_get_args()), function () use($__function__, $__method__) {
172+
return \'chi\';
173+
});
174+
}
175+
}', $code);
176+
}
177+
116178
public function testParentMethods()
117179
{
118180
$ast = new Ast();

tests/Stub/Ast/Abs.php

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace HyperfTest\Di\Stub\Ast;
13+
14+
abstract class Abs
15+
{
16+
public function abs(): string
17+
{
18+
return 'abs';
19+
}
20+
21+
abstract public function absabs(): string;
22+
}

tests/Stub/Ast/AbsAspect.php

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace HyperfTest\Di\Stub\Ast;
13+
14+
use Hyperf\Di\Aop\AbstractAspect;
15+
use Hyperf\Di\Aop\ProceedingJoinPoint;
16+
17+
class AbsAspect extends AbstractAspect
18+
{
19+
public array $classes = [
20+
Abs::class,
21+
Chi::class,
22+
];
23+
24+
public function process(ProceedingJoinPoint $proceedingJoinPoint)
25+
{
26+
return $proceedingJoinPoint->process();
27+
}
28+
}

tests/Stub/Ast/Chi.php

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace HyperfTest\Di\Stub\Ast;
13+
14+
class Chi extends Abs
15+
{
16+
public function absabs(): string
17+
{
18+
return 'chi';
19+
}
20+
}

0 commit comments

Comments
 (0)