Laravel 标记所有实现接口(interface)的类

标签 laravel interface tags bind

我正在使用 Laravel 8,我想获取所有实现接口(interface) X 的类。

我几个月前用 DI 用 symfony4 做到了:

服务.yml

_instanceof:
    App\Calculator\Budget\BudgetCalculatorInterface:
      tags: ['app.budget_calculator']
App\Handler\CalculatorBudgetHandler:
  arguments: [!tagged app.budget_calculator]

然后在我的类(class) CalculatorBudgetHandler.php 中

private $calculatorList = [];

public function __construct(iterable $calculatorList)
{
    $this->calculatorList = $calculatorList;
}

public function __construct(iterable $calculatorList)
{
    $this->calculatorList = $calculatorList;
}

public function calculate(array $data): float
{
    foreach ($this->calculatorList as $calculator) {
        if ($calculator->supports($data)) {
            return $calculator->calculate($data);
        }
    }

  
}

但我不明白如何用 Laravel 做到这一点。我想我必须在绑定(bind)或标记中传递我所有的类:

$this->app->tag([CpuReport::class, MemoryReport::class], 'reports');

这意味着如果我有一个实现 X 的新类,我必须将它添加到绑定(bind)/标记中? 我想自动执行。

谢谢!

最佳答案

我也需要这个。找了半天,基本上找到了解决办法。这样做的坏处是,在 PHP 中,当您没有使用 类时,它们实际上并没有被声明。因此,您必须扫描整个项目以查找类并测试每个类以找到实现您的接口(interface)的类,或者(更好)您使用 Composer 自动加载类映射。在那里,您可能会将类的搜索范围限制为子 namespace 。

以这种方式工作的小而酷的包是这个:https://gitlab.com/hpierce1102/ClassFinder - 基本上它使用 composer PSR4 classmaps 并且总体上表现良好。

这是我得出的解决方案:

// Add to service provider
private function tagByInterface(string $interfaceName, string $tagName, string $rootNamespace)
{
    foreach (ClassFinder::getClassesInNamespace($rootNamespace, ClassFinder::RECURSIVE_MODE) as $className) {
        $class = new \ReflectionClass($className);
        if ($class->isAbstract() || $class->isInterface()) {
            continue;
        }

        if ($class->implementsInterface($interfaceName)) {
            $this->app->tag($className, $tagName);
        }
    }
}

然后可以在 register() 中像这样使用:

$this->tagByInterface(SomeInterface::class, 'some-tag', 'App\Domain\Something');

$this->app->when(SomeClass::class)->needs('$myServices')->giveTagged('some-tag');

由于类是使用反射加载的,如果您的根命名空间设置不正确或太宽,此操作仍可能需要一些时间。反射很快(据我所知比从缓存中加载信息更快),但您仍然应该考虑为任务使用延迟提供程序,以便仅在实际需要时触发对实现类的搜索。

关于Laravel 标记所有实现接口(interface)的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66947862/

相关文章:

javascript - 从 Laravel Blade 循环获取 JavaScript 的变量类名

Laravel 5.3 php artisan 迁移不工作

mysql - 基表或 View 已存在! (拉拉维尔航海者)

ios - Dropzone 在 iOS 11 上失败

java - Kotlin 函数式接口(interface) java 兼容性

go - golang中如何匹配两个接口(interface)

多维矩阵的Java接口(interface)设计

php - WordPress/mySQL 如何将标签与帖子关联起来

perl - 在 Raku 中使用 Perl 5 模块 Data::Printer 的 `show_tied` 选项时,如何关闭它?

android - <hr>标签在android中的使用