美文网首页
laravel 中实现注解注入

laravel 中实现注解注入

作者: guanguans | 来源:发表于2024-10-15 14:29 被阅读0次

    laravel 中实现注解注入

    创建注解类

    <?php
    
    declare(strict_types=1);
    
    namespace App\Support\Attributes;
    
    #[\Attribute(\Attribute::TARGET_PROPERTY)]
    readonly class Injection
    {
        public function __construct(
            public ?string $propertyType = null,
            public array $parameters = []
        ) {}
    }
    

    引导解析注解

    <?php
    
    declare(strict_types=1);
    
    namespace App\Providers;
    
    use App\Support\Attributes\Injection;
    use Illuminate\Foundation\Application;
    use Illuminate\Support\ServiceProvider;
    
    class AppServiceProvider extends ServiceProvider
    {
        public function register(): void {}
    
        public function boot(): void
        {
            $this->injection();
        }
    
        private function injection(): void
        {
            $this->app->resolving(static function (mixed $object, Application $app): void {
                if (! \is_object($object)) {
                    return;
                }
    
                $class = str($object::class);
                if (
                    ! $class->is(config('services.injection.only'))
                    || $class->is(config('services.injection.except'))
                ) {
                    return;
                }
    
                $reflectionObject = new \ReflectionObject($object);
    
                foreach ($reflectionObject->getProperties() as $reflectionProperty) {
                    if (! $reflectionProperty->isDefault() || $reflectionProperty->isStatic()) {
                        continue;
                    }
    
                    $attributes = $reflectionProperty->getAttributes(Injection::class);
                    if ($attributes === []) {
                        continue;
                    }
    
                    /** @var Injection $injection */
                    $injection = $attributes[0]->newInstance();
    
                    $propertyType = value(static function () use ($injection, $reflectionProperty, $reflectionObject): string {
                        if ($injection->propertyType) {
                            return $injection->propertyType;
                        }
    
                        $reflectionPropertyType = $reflectionProperty->getType();
                        if ($reflectionPropertyType instanceof \ReflectionNamedType && ! $reflectionPropertyType->isBuiltin()) {
                            return $reflectionPropertyType->getName();
                        }
    
                        throw new \LogicException(\sprintf(
                            'Attribute [%s] of %s miss a argument, or %s must be a non-built-in named type.',
                            Injection::class,
                            $property = "property [{$reflectionObject->getName()}::\${$reflectionProperty->getName()}]",
                            $property,
                        ));
                    });
    
                    $reflectionProperty->isPublic() or $reflectionProperty->setAccessible(true);
                    $reflectionProperty->setValue($object, $app->make($propertyType, $injection->parameters));
                }
            });
        }
    }
    

    配置解析范围(可选)

    config/services.php

    <?php
    
    return [
        // ...
    
        'injection' => [
            'only' => [
                'App\*',
            ],
            'except' => [
                'App\Support\Macros\*',
            ],
        ],
    ];
    

    使用

    示例

    <?php
    
    declare(strict_types=1);
    
    namespace App\Console\Commands;
    
    use App\Support\Attributes\Injection;
    use App\Support\HmacSigner;
    use Illuminate\Config\Repository;
    
    class TestCommand extends \Illuminate\Console\Command
    {
        protected $signature = 'test';
    
        #[Injection('path.storage')]
        private string $storagePath;
    
        #[Injection(parameters: ['secret' => 'secret...'])]
        private HmacSigner $hmacSigner;
    
        #[Injection(Repository::class)]
        private Repository $repositoryOfInjectionPropertyType;
    
        #[Injection('config')]
        private Repository $repositoryOfInjectionInstanceKey;
    
        #[Injection]
        private Repository $repositoryOfReflectionPropertyType;
    
        public function handle(): void
        {
            dump(
                $this->storagePath,
                $this->hmacSigner,
                $this->repositoryOfInjectionPropertyType->get('services.injection'),
                $this->repositoryOfInjectionInstanceKey->get('services.injection.only'),
                $this->repositoryOfReflectionPropertyType->get('services.injection.except'),
            );
        }
    }
    

    输出

    ╰─ ./artisan test                                                                                ─╯
    "/Users/yaozm/Documents/wwwroot/laravel-skeleton/storage" // app/Console/Commands/TestCommand.php:32
    App\Support\HmacSigner {#2045
      -secret: "secret..."
      -algo: "sha256"
    } // app/Console/Commands/TestCommand.php:32
    array:2 [
      "only" => array:1 [
        0 => "App\*"
      ]
      "except" => array:1 [
        0 => "App\Support\Macros\*"
      ]
    ] // app/Console/Commands/TestCommand.php:32
    array:1 [
      0 => "App\*"
    ] // app/Console/Commands/TestCommand.php:32
    array:1 [
      0 => "App\Support\Macros\*"
    ] // app/Console/Commands/TestCommand.php:32
    

    与依赖注入比较

    功能 注解注入 依赖注入
    标量类型 已支持 未支持
    传参 已支持 未支持

    相关连接

    原文连接

    相关文章

      网友评论

          本文标题:laravel 中实现注解注入

          本文链接:https://www.haomeiwen.com/subject/yyrtdjtx.html