首页 >后端开发 >php教程 >PHP主|使用PSR-3登录以提高可重用性

PHP主|使用PSR-3登录以提高可重用性

尊渡假赌尊渡假赌尊渡假赌
尊渡假赌尊渡假赌尊渡假赌原创
2025-02-24 10:42:15977浏览

PHP Master | Logging with PSR-3 to Improve Reusability

核心要点

  • PSR-3,一个通用的日志对象接口,允许开发者编写可重用的代码,而无需依赖任何特定的日志实现,从而提高了PHP中不同日志库之间的兼容性。
  • PSR-3接口提供了八种方法来处理不同严重级别的消息,以及一个通用的log()方法,可以接收任意严重级别。其设计目的是为了解决日志实现不兼容的问题。
  • 尽管PSR-3有很多好处,但有些日志库并不原生支持它。然而,开发者可以通过利用适配器模式和扩展Psr/Log库中提供的AbstractLogger类来创建符合PSR-3的适配器。
  • 许多主要的PHP项目,包括Monolog、Symfony和Mustache.php,都已经添加了对PSR-3的支持。由于它降低了代码重用的障碍,预计会有更多库和框架正确使用日志记录,为开发者提供有用的信息。

在PHP开发中,日志记录是最常见的任务之一。我们使用日志来跟踪错误消息、记录重要事件和调试代码问题。在任何PHP项目中,代码中都可能充满了对日志库的调用,这些库为我们处理这些操作。不幸的是,在代码中散布着对日志库的调用,这使得代码依赖于该库的可用性,这明显违反了依赖倒置原则。即使我们使用依赖注入让我们的对象访问日志库,日志库之间的差异也意味着在它们之间切换可能很困难且费时,需要对整个代码库进行重大重构。为了提高日志库之间的兼容性,PHP-FIG小组最近发布了PSR-3,这是一个通用的日志对象接口。在本文中,我将讨论PSR-3定义的日志接口如何允许我们编写不依赖于任何特定日志实现的可重用代码。

PSR-3快速入门

在我们了解PSR-3如何使我们的代码更可重用之前,有必要了解PSR-3是什么。如果您已经熟悉PSR-3,可以跳过本节。规范的核心是日志对象的接口。此接口公开了八种方法来处理不同严重级别的消息,以及一个通用的log()方法,可以接受任意严重级别。PSR-3支持的八个严重级别基于RFC 5424,如下所述:

  • emergency – 系统无法使用
  • alert – 需要立即采取行动
  • critical – 严重状况
  • error – 不需要立即关注但应监控的错误
  • warning – 不寻常或不希望发生的事件,但并非错误
  • notice – 正常但重要的事件
  • info – 有趣的事件
  • debug – 用于调试的详细信息

每个日志方法都接受一个消息,该消息必须是字符串或具有__toString()方法的对象。附加参数接受一个数组,可以提供日志消息的上下文信息。可以在PSR-3规范中找到这些方法和参数的完整说明。

获取PSR-3文件

获取使用PSR-3所需的文件很容易——您可以在Psr/Log GitHub存储库中找到它们。您也可以使用Composer从Packagist获取这些文件。下面是一个用于检索Psr/Log文件的示例composer.json文件:

<code class="language-json">{
    "require": {
        "psr/log": "dev-master"
    }
}</code>

日志记录如何限制代码重用

PHP有很多不同的日志库,每个库都有自己收集和记录数据的方法。虽然它们之间有一些共同点,但每个库都有自己独特的一套日志方法。这意味着在日志之间切换可能具有挑战性,通常需要更改任何使用日志记录的地方的代码。这与代码重用和面向对象设计的SOLID原则背道而驰。我们面临的局面是:要么声明对特定日志库的依赖,要么完全避免日志记录。为了更清楚地说明这个问题,需要一个具体的例子。假设我们正在创建一个简单的Mailer对象来处理发送电子邮件。我们希望Mailer在每次发送电子邮件时记录一条消息,并且我们决定使用优秀的Monolog库来处理我们的日志记录需求。

<code class="language-php"><?php namespace Email;

class Mailer
{
    private $logger;

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

    public function sendEmail($emailAddress)
    {
        // 发送电子邮件的代码...

        // 记录消息
        $this->logger->addInfo("Email sent to $emailAddress");
    }
}</code>

我们可以使用以下代码使用此类:

<code class="language-php"><?php
// 创建一个Monolog对象
$logger = new Monolog\Logger("Mail");
$logger->pushHandler(new Monolog\Handler\StreamHandler("mail.log"));

// 创建邮件发送器并发送电子邮件
$mailer = new Email\Mailer($logger);
$mailer->sendEmail("email@example.com");</code>

运行此代码将在mail.log文件中创建一个新条目,记录已发送电子邮件。此时,我们可能会认为我们已经编写了一个可重用的Mailer对象。我们使用依赖注入使日志记录器可用于Mailer,因此我们可以交换不同的日志记录器配置,而无需触及我们的Mailer代码。看起来我们已经成功遵循了SOLID原则并避免了创建任何硬依赖。但是,假设我们想在使用Analog处理日志记录交互的不同项目中重用Mailer类。现在我们遇到了问题,因为Analog没有addInfo()方法。要使用Analog记录信息级别消息,我们调用Analog::log($message, Analog::INFO)。我们可以修改Mailer类以使用Analog的方法,如下所示。

<code class="language-php"><?php namespace Email;

class Mailer
{
    public function sendEmail($emailAddress)
    {
        // 发送电子邮件的代码...

        // 记录消息
        Analog::log("Email sent to $emailAddress", Analog::INFO);
    }
}</code>

我们可以使用以下代码使用更新后的Mailer类:

<code class="language-json">{
    "require": {
        "psr/log": "dev-master"
    }
}</code>

虽然这会起作用,但这远非理想。我们遇到了Mailer对特定日志记录实现的依赖,这要求在引入新的日志记录器时更改类。这使得类不太可重用,并迫使我们必须在依赖于特定日志记录器的可用性或完全放弃类中的日志记录之间做出选择。

使用PSR-3避免日志记录器依赖

正如Alejandro Gervasio在他关于该主题的优秀文章中解释的那样,依赖倒置原则告诉我们,我们应该依赖抽象而不是具体实现。在日志记录的情况下,我们目前的问题一直是缺乏一个可以依赖的合适的抽象。这就是PSR-3发挥作用的地方。PSR-3旨在通过为日志记录器提供一个通用接口(恰当地命名为LoggerInterface)来克服日志记录实现不兼容的问题。通过提供一个不绑定到任何特定实现的接口,PSR-3使我们无需依赖特定的日志记录器——我们可以改为对LoggerInterface进行类型提示以获取符合PSR-3的日志记录器。我已经更新了下面的Mailer类来演示这一点:

<code class="language-php"><?php namespace Email;

class Mailer
{
    private $logger;

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

    public function sendEmail($emailAddress)
    {
        // 发送电子邮件的代码...

        // 记录消息
        $this->logger->addInfo("Email sent to $emailAddress");
    }
}</code>

构造函数已修改为接受LoggerInterface的实现者,并且sendEmail()方法现在调用PSR-3中指定的info()方法。Monolog已经符合PSR-3,并且Analog提供了一个实现LoggerInterface的包装器对象,因此我们现在可以使用这两个日志记录器而无需修改Mailer类。以下是如何使用Monolog调用该类的:

<code class="language-php"><?php
// 创建一个Monolog对象
$logger = new Monolog\Logger("Mail");
$logger->pushHandler(new Monolog\Handler\StreamHandler("mail.log"));

// 创建邮件发送器并发送电子邮件
$mailer = new Email\Mailer($logger);
$mailer->sendEmail("email@example.com");</code>

以及使用Analog:

<code class="language-php"><?php namespace Email;

class Mailer
{
    public function sendEmail($emailAddress)
    {
        // 发送电子邮件的代码...

        // 记录消息
        Analog::log("Email sent to $emailAddress", Analog::INFO);
    }
}</code>

现在,我们能够使用我们的Mailer对象与任何库一起使用,而无需编辑Mailer类或更改我们使用它的方式。

为不支持PSR-3的日志记录器使用适配器模式

到目前为止,我们已经通过请求LoggerInterface的实现者成功地将Mailer对象与任何特定的日志记录实现解耦。但是,那些尚未添加对PSR-3支持的日志记录器呢?例如,流行的KLogger库已经有一段时间没有更新了,目前与PSR-3不兼容。幸运的是,我们可以通过利用适配器模式轻松地将KLogger公开的方法映射到LoggerInterface中定义的方法。Psr/Log存储库中的支持文件使我们能够通过提供一个我们可以扩展的AbstractLogger类来轻松创建适配器类。抽象类只是将LoggerInterface中定义的八个特定于级别的日志方法转发到一个通用的log()方法。通过扩展AbstractLogger类并定义我们自己的log()方法,我们可以轻松地为不原生支持PSR-3的日志记录器创建符合PSR-3的适配器。我将在下面通过为KLogger创建一个简单的适配器来演示这一点:

<code class="language-json">{
    "require": {
        "psr/log": "dev-master"
    }
}</code>

log()方法只是将LoggerInterface方法映射到各自的KLogger方法,而KLogger处理实际的日志记录活动。通过这种方式包装KLogger类,我们能够在不破坏LoggerInterface契约的情况下使用它。我们现在可以使用KLogger适配器与Mailer类一起使用:

<code class="language-php"><?php namespace Email;

class Mailer
{
    private $logger;

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

    public function sendEmail($emailAddress)
    {
        // 发送电子邮件的代码...

        // 记录消息
        $this->logger->addInfo("Email sent to $emailAddress");
    }
}</code>

使用适配器类,我们能够在不修改Mailer类的情况下使用KLogger,并且仍然遵守LoggerInterface。KLogger不接受调试级别消息的第二个参数,因此即使使用适配器,它也不完全符合PSR-3。扩展KLogger以使其完全与PSR-3兼容将是一项微不足道的任务,但这超出了本文的范围。但是,可以肯定地说,使用我们的适配器类使我们非常接近完全符合PSR-3,并允许我们使用LoggerInterface与KLogger类一起使用。

结论

在本文中,我们已经了解了如何使用PSR-3来帮助我们编写与日志记录器无关的代码,这些代码不依赖于特定的日志记录实现。许多主要的PHP项目已经添加了对PSR-3的支持,包括Monolog、Symfony和Mustache.php,以及Drupal等其他知名项目正在讨论如何最好地集成它。由于PSR-3降低了代码重用的障碍,我们应该看到更多库和框架正确使用日志记录,为开发者提供有用的信息。PSR-3会影响您在应用程序中使用日志记录的方式吗?请在下面的评论部分告诉我们。

(图片来自Fotolia)

(PSR-3日志记录的常见问题解答部分,由于篇幅限制,此处省略。 可以根据需要添加。)

以上是PHP主|使用PSR-3登录以提高可重用性的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn