Merge branch 'master' into pr/1488

This commit is contained in:
huangzhhui 2020-04-02 11:21:28 +08:00
commit 06044f40de
6 changed files with 104 additions and 30 deletions

View File

@ -38,6 +38,10 @@
- [#1452](https://github.com/hyperf/hyperf/pull/1452) Encourage the use of `\Hyperf\Redis\Redis` instead of `\Redis` because of [#938](https://github.com/hyperf/hyperf/issues/938).
## Added
- [#1480](https://github.com/hyperf/hyperf/pull/1480) RPC client will generate the methods of inherited interface automatically now.
# v1.1.21 - 2020-03-19
## Added

View File

@ -22,7 +22,8 @@
"psr/container": "^1.0",
"hyperf/rpc": "~1.1.0",
"hyperf/load-balancer": "~1.1.0",
"hyperf/utils": "~1.1.0"
"hyperf/utils": "~1.1.0",
"roave/better-reflection": "^4.0"
},
"require-dev": {
"malukenho/docheader": "^0.1.6",

View File

@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Hyperf\RpcClient\Proxy;
use Hyperf\Utils\Composer;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter\Standard;
@ -23,18 +22,24 @@ class Ast
/**
* @var \PhpParser\Parser
*/
private $astParser;
protected $astParser;
/**
* @var PrettyPrinterAbstract
*/
private $printer;
protected $printer;
/**
* @var CodeLoader
*/
protected $codeLoader;
public function __construct()
{
$parserFactory = new ParserFactory();
$this->astParser = $parserFactory->create(ParserFactory::ONLY_PHP7);
$this->printer = new Standard();
$this->codeLoader = new CodeLoader();
}
public function proxy(string $className, string $proxyClassName)
@ -47,20 +52,11 @@ class Ast
$proxyClassName = end($exploded);
}
$code = $this->getCodeByClassName($className);
$code = $this->codeLoader->getCodeByClassName($className);
$stmts = $this->astParser->parse($code);
$traverser = new NodeTraverser();
$traverser->addVisitor(new ProxyCallVisitor($proxyClassName));
$modifiedStmts = $traverser->traverse($stmts);
return $this->printer->prettyPrintFile($modifiedStmts);
}
public function getCodeByClassName(string $className): string
{
$file = Composer::getLoader()->findFile($className);
if (! $file) {
return '';
}
return file_get_contents($file);
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\RpcClient\Proxy;
use Hyperf\Utils\Composer;
class CodeLoader
{
public function getCodeByClassName(string $className): string
{
$file = Composer::getLoader()->findFile($className);
if (! $file) {
return '';
}
return file_get_contents($file);
}
}

View File

@ -15,22 +15,43 @@ namespace Hyperf\RpcClient\Proxy;
use PhpParser\Node;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\NodeVisitorAbstract;
use ReflectionMethod;
use Roave\BetterReflection\Reflection\ReflectionClass;
class ProxyCallVisitor extends NodeVisitorAbstract
{
/**
* @var string
*/
private $classname;
/**
* @var string
*/
private $namespace;
/**
* @var array
*/
private $constants = [];
public function __construct(string $classname)
{
$this->classname = $classname;
}
public function enterNode(Node $node)
{
if ($node instanceof Node\Stmt\Namespace_) {
$this->namespace = $node->name->toCodeString();
}
}
public function leaveNode(Node $node)
{
if ($node instanceof Interface_) {
$node->stmts = $this->generateStmts($node);
return new Node\Stmt\Class_($this->classname, [
'stmts' => $node->stmts,
'extends' => new Node\Name\FullyQualified(AbstractProxyService::class),
@ -39,19 +60,37 @@ class ProxyCallVisitor extends NodeVisitorAbstract
],
]);
}
if ($node instanceof Node\Stmt\ClassMethod) {
$node->stmts = [
new Node\Stmt\Return_(new Node\Expr\MethodCall(
new Node\Expr\PropertyFetch(new Node\Expr\Variable('this'), new Node\Identifier('client')),
new Node\Identifier('__call'),
[
new Node\Scalar\MagicConst\Function_(),
new Node\Expr\FuncCall(new Node\Name('func_get_args')),
]
)),
];
return $node;
}
return parent::leaveNode($node); // TODO: Change the autogenerated stub
}
public function generateStmts(Interface_ $node): array
{
$betterReflectionInterface = ReflectionClass::createFromName($this->namespace . '\\' . $node->name);
$reflectionMethods = $betterReflectionInterface->getMethods(ReflectionMethod::IS_PUBLIC);
$stmts = [];
foreach ($reflectionMethods as $method) {
$stmts[] = $this->overrideMethod($method->getAst());
}
return $stmts;
}
protected function overrideMethod(Node\Stmt\ClassMethod $stmt): Node\Stmt\ClassMethod
{
$stmt->stmts = value(function () use ($stmt) {
$methodCall = new Node\Expr\MethodCall(
new Node\Expr\PropertyFetch(new Node\Expr\Variable('this'), new Node\Identifier('client')),
new Node\Identifier('__call'),
[
new Node\Scalar\MagicConst\Function_(),
new Node\Expr\FuncCall(new Node\Name('func_get_args')),
]
);
if (((string) $stmt->getReturnType()) !== 'void') {
return [new Node\Stmt\Return_($methodCall)];
} else {
return [new Node\Stmt\Expression($methodCall)];
}
});
return $stmt;
}
}

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace Hyperf\RpcClient;
use Hyperf\RpcClient\Proxy\Ast;
use Hyperf\RpcClient\Proxy\CodeLoader;
use Hyperf\Utils\Coroutine\Locker;
use Hyperf\Utils\Traits\Container;
@ -23,11 +24,17 @@ class ProxyFactory
/**
* @var Ast
*/
private $ast;
protected $ast;
/**
* @var \Hyperf\RpcClient\Proxy\CodeLoader
*/
protected $codeLoader;
public function __construct()
{
$this->ast = new Ast();
$this->codeLoader = new CodeLoader();
}
public function createProxy($serviceClass): string
@ -41,7 +48,7 @@ class ProxyFactory
}
$proxyFileName = str_replace('\\', '_', $serviceClass);
$proxyClassName = $serviceClass . '_' . md5($this->ast->getCodeByClassName($serviceClass));
$proxyClassName = $serviceClass . '_' . md5($this->codeLoader->getCodeByClassName($serviceClass));
$path = $dir . $proxyFileName . '.proxy.php';
$key = md5($path);