如何在Symfony 4中将LoggerInterface服务公开?

3
我希望Symfony中的Psr\Log\LoggerInterface公共,这样我就可以直接从容器中获取它,使用$container->get('Psr\Log\LoggerInterface')
我尝试了以下的services.yaml
_defaults:
 public: true

Psr\Log\LoggerInterface:
 public: true

Psr\Log\LoggerInterface:
 alias: 'logger'
 public: true

Psr\Log\LoggerInterface:
 alias: 'monolog.logger'
 public: true

我不明白为什么重写一个服务如此困难。

最初的回答:


$container->get('logger')将获取日志记录器,假设您可以访问完整的容器。您是想从控制器还是某个服务中访问日志记录器? - undefined
3个回答

4

正如先前所述,不鼓励直接从容器访问服务。但我有点好奇如何将私有服务公开。我尝试了问题中列出的方法,并确认它没有成功。

这可能不是最简单的方法,但编译器传递可以解决问题:

# src/Kernel.php
# Make the kernel a compiler pass
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class Kernel extends BaseKernel implements CompilerPassInterface
...
public function process(ContainerBuilder $container)
{
    $logger = $container->getAlias(LoggerInterface::class);
    $logger->setPublic(true);
}

# And that should do the trick, you can confirm with
bin/console debug:container Psr\Log\LoggerInterface

请注意,只有完整容器被注入的服务才能利用此功能。继承自AbstractController的控制器仅能访问少量服务。

如果您在控制器中需要记录器,或者只是想要更好的方法,请查看服务订阅者


1
每个人都说直接使用容器是一个不好的做法。然而有两点。第一,没有人知道我的情况。其次,有一个服务没有声明构造函数参数,但实际上它并不需要这些参数,而是为了它的子服务。 - undefined
“@required”听起来很有趣。你是指这个网址吗:http://php-di.org/doc/annotations.html? - undefined
错误的容器。 老实说,我不确定文档在哪里记录。查了几次但没有找到。这里 有一些讨论。并且在这里有一个运行示例,使用它将路由注入到RouteTrait中。然后您可以在需要路由功能的任何其他服务中使用RouterTrait而无需担心注入路由器。有点神奇,但我觉得它很有用。 - undefined
这太棒了。但是请记住,Symfony容器不支持PHP_DI容器支持的所有注解。这是两个完全不同的代码库。我不认为“@Inject”可以直接使用。不确定你所说的“冗余”是什么意思。我只为常用的服务创建traits。否则,我只使用构造函数注入。祝你好运。 - undefined
2
这段代码是否适用于3.4及更高版本?我已经将其添加到我的appKernel.php中(我正在迁移一个旧的2.7应用程序),并在调试器中验证了它的运行,但尽管设置了public属性,当下次请求服务时,它仍然显示在私有服务列表中。编辑 - 是的,适用。我只需要将服务名称更改为'logger',即$container->getAlias('logger')。哎呀,如此简单! - undefined
显示剩余4条评论

0

不确定它是否适用于您的情况,但在我的情况下,我需要测试中的monolog.logger服务的公共版本以进行模拟。因此,我创建了一个公共别名:

test.monolog.logger:
  alias: 'Psr\Log\LoggerInterface'
  public: true

现在,当我使用 DI 注入 LoggerInterface 类时,我会得到这个服务,在我的测试中进行了模拟:

$loggerMock = $this->createMock(LoggerInterface::class);
static::getContainer()->set("test.monolog.logger", $loggerMock);

-4

使用$container->get()是一个不好的实践。它违反了许多良好的软件设计原则。

你应该使用构造函数注入代替。

class Foo
{
    protected $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}

我也给这个答案点了踩。它并没有事实上的错误,但它没有回答我如何做到这一点的问题。有时候你只是不得不这样做。我喜欢Symfony试图引导你遵循良好的设计原则,但当你需要打破它们时,知道如何做会很好。 - undefined
@zquintana 谢谢你的负评。你和其他给我负评的人教会了我一个很好的教训。我非常感激。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接