Allow lazy injection through @Inject(lazy=true)

This commit is contained in:
Reasno 2019-11-30 15:25:32 +08:00
parent 6d31026013
commit a595c3ae32
6 changed files with 38 additions and 20 deletions

View File

@ -32,6 +32,11 @@ class Inject extends AbstractAnnotation
*/
public $required = true;
/**
* @var bool
*/
public $lazy = false;
/**
* @var PhpDocReader
*/
@ -48,6 +53,9 @@ class Inject extends AbstractAnnotation
try {
$this->value = $this->docReader->getPropertyClass(ReflectionManager::reflectClass($className)->getProperty($target));
AnnotationCollector::collectProperty($className, $target, static::class, $this);
if ($this->lazy) {
$this->value = 'HyperfLazy\\' . $this->value;
}
} catch (AnnotationException $e) {
if ($this->required) {
throw $e;

View File

@ -14,9 +14,12 @@ namespace Hyperf\Di\LazyLoader;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Utils\Coroutine\Locker as CoLocker;
use Hyperf\Utils\Str;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter\Standard;
use ReflectionClass;
class LazyLoader
{
@ -32,7 +35,7 @@ class LazyLoader
/**
* The singleton instance of the loader.
*
* @var \Hyperf\Di\LazyLoader\LazyLoader
* @var LazyLoader
*/
protected static $instance;
@ -51,8 +54,6 @@ class LazyLoader
/**
* Get or create the singleton lazy loader instance.
*
* @return \Hyperf\Di\LazyLoader\LazyLoader
*/
public static function bootstrap(ConfigInterface $config): LazyLoader
{
@ -69,7 +70,7 @@ class LazyLoader
*/
public function load(string $proxy)
{
if ($this->config->get($proxy, false)) {
if (array_key_exists($proxy, $this->config) || Str::startsWith($proxy, 'HyperfLazy\\')) {
$this->loadProxy($proxy);
return true;
}
@ -110,7 +111,7 @@ class LazyLoader
$targetPath = $path . '.' . uniqid();
$code = $this->generatorLazyProxy(
$proxy,
$this->config->get($proxy)
$this->config[$proxy] ?? Str::after($proxy, 'HyperfLazy\\')
);
file_put_contents($targetPath, $code);
rename($targetPath, $path);
@ -124,7 +125,7 @@ class LazyLoader
*/
protected function generatorLazyProxy(string $proxy, string $target): string
{
$targetReflection = new \ReflectionClass($target);
$targetReflection = new ReflectionClass($target);
$fileName = $targetReflection->getFileName();
if (! $fileName) {
$code = ''; // Classes and Interfaces from PHP internals
@ -148,7 +149,7 @@ class LazyLoader
*/
protected function prependToLoaderStack(): void
{
/** @var callable(string): void*/
/** @var callable(string): void */
$load = [$this, 'load'];
spl_autoload_register($load, true, true);
}
@ -159,10 +160,10 @@ class LazyLoader
*
* TODO: implement some of them.
*
* @param \ReflectionClass $targetReflection [description]
* @param ReflectionClass $targetReflection [description]
* @return bool [description]
*/
private function isUnsupportedReflectionType(\ReflectionClass $targetReflection): bool
private function isUnsupportedReflectionType(ReflectionClass $targetReflection): bool
{
//Final class
if ($targetReflection->isFinal()) {
@ -199,7 +200,7 @@ class LazyLoader
$traverser->addVisitor($visitor);
$ast = $traverser->traverse($ast);
$builder->addNodes($visitor->nodes);
$prettyPrinter = new \PhpParser\PrettyPrinter\Standard();
$prettyPrinter = new Standard();
$stmts = [$builder->getNode()];
return $prettyPrinter->prettyPrintFile($stmts);
}

View File

@ -20,6 +20,7 @@ use PhpParser\Node\Name;
use PhpParser\Node\Scalar\MagicConst\Function_ as MagicConstFunction;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use PhpParser\NodeVisitorAbstract;
@ -36,10 +37,15 @@ class PublicMethodVisitor extends NodeVisitorAbstract
{
if ($node instanceof ClassMethod) {
$methodCall =
new Return_(new MethodCall(new Variable('this'), '__call', [
new MethodCall(new Variable('this'), '__call', [
new Node\Arg(new MagicConstFunction()),
new Node\Arg(new FuncCall(new Name('func_get_args'))),
]));
]);
if ($node->returnType && $node->returnType->toString() !== 'void') {
$methodCall = new Return_($methodCall);
} else {
$methodCall = new Expression($methodCall);
}
$node->stmts = [
$methodCall,
];

View File

@ -17,6 +17,7 @@ use Hyperf\Di\LazyLoader\PublicMethodVisitor;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter\Standard;
use PHPUnit\Framework\TestCase;
/**
@ -63,7 +64,7 @@ class SomeClass extends \App\SomeClass
}
public function it(\bar\ConfigInterface $a) : void
{
return $this->__call(__FUNCTION__, func_get_args());
$this->__call(__FUNCTION__, func_get_args());
}
public function works(bool $a, float $b = 1) : int
{
@ -84,7 +85,7 @@ CODETEMPLATE;
$traverser->addVisitor($visitor);
$ast = $traverser->traverse($ast);
$builder->addNodes($visitor->nodes);
$prettyPrinter = new \PhpParser\PrettyPrinter\Standard();
$prettyPrinter = new Standard();
$stmts = [$builder->getNode()];
$newCode = $prettyPrinter->prettyPrintFile($stmts);
$this->assertEquals($expected, $newCode);

View File

@ -17,6 +17,7 @@ use Hyperf\Di\LazyLoader\PublicMethodVisitor;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter\Standard;
use PHPUnit\Framework\TestCase;
/**
@ -60,7 +61,7 @@ class SomeClass implements \App\SomeInterface
}
public function it(\bar\ConfigInterface $a) : void
{
return $this->__call(__FUNCTION__, func_get_args());
$this->__call(__FUNCTION__, func_get_args());
}
public function works(bool $a, float $b = 1) : int
{
@ -81,7 +82,7 @@ CODETEMPLATE;
$traverser->addVisitor($visitor);
$ast = $traverser->traverse($ast);
$builder->addNodes($visitor->nodes);
$prettyPrinter = new \PhpParser\PrettyPrinter\Standard();
$prettyPrinter = new Standard();
$stmts = [$builder->getNode()];
$newCode = $prettyPrinter->prettyPrintFile($stmts);
$this->assertEquals($expected, $newCode);

View File

@ -15,6 +15,7 @@ namespace HyperfTest\Di;
use Hyperf\Di\LazyLoader\PublicMethodVisitor;
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter\Standard;
use PHPUnit\Framework\TestCase;
/**
@ -45,7 +46,7 @@ public function hope(bool $a) : int
}
public function it(ConfigInterface $a) : void
{
return $this->__call(__FUNCTION__, func_get_args());
$this->__call(__FUNCTION__, func_get_args());
}
public function works(bool $a, float $b = 1) : int
{
@ -58,7 +59,7 @@ CODETEMPLATE;
$visitor = new PublicMethodVisitor();
$traverser->addVisitor($visitor);
$ast = $traverser->traverse($ast);
$prettyPrinter = new \PhpParser\PrettyPrinter\Standard();
$prettyPrinter = new Standard();
$newCode = $prettyPrinter->prettyPrintFile($visitor->nodes);
$this->assertEquals($expected, $newCode);
}
@ -90,7 +91,7 @@ public function hope(bool $a) : int
}
public function it(ConfigInterface $a) : void
{
return $this->__call(__FUNCTION__, func_get_args());
$this->__call(__FUNCTION__, func_get_args());
}
public function works(bool $a, float $b = 1) : int
{
@ -103,7 +104,7 @@ CODETEMPLATE;
$visitor = new PublicMethodVisitor();
$traverser->addVisitor($visitor);
$ast = $traverser->traverse($ast);
$prettyPrinter = new \PhpParser\PrettyPrinter\Standard();
$prettyPrinter = new Standard();
$newCode = $prettyPrinter->prettyPrintFile($visitor->nodes);
$this->assertEquals($expected, $newCode);
$this->assertEquals(3, count($visitor->nodes));