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

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

Feb 24, 2025 am 10:42 AM

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文件:

{
    "require": {
        "psr/log": "dev-master"
    }
}
登录后复制
登录后复制
登录后复制

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

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

<?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");
    }
}
登录后复制
登录后复制
登录后复制

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

<?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");
登录后复制
登录后复制

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

<?php namespace Email;

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

        // 记录消息
        Analog::log("Email sent to $emailAddress", Analog::INFO);
    }
}
登录后复制
登录后复制

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

{
    "require": {
        "psr/log": "dev-master"
    }
}
登录后复制
登录后复制
登录后复制

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

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

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

<?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");
    }
}
登录后复制
登录后复制
登录后复制

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

<?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");
登录后复制
登录后复制

以及使用Analog:

<?php namespace Email;

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

        // 记录消息
        Analog::log("Email sent to $emailAddress", Analog::INFO);
    }
}
登录后复制
登录后复制

现在,我们能够使用我们的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创建一个简单的适配器来演示这一点:

{
    "require": {
        "psr/log": "dev-master"
    }
}
登录后复制
登录后复制
登录后复制

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

<?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");
    }
}
登录后复制
登录后复制
登录后复制

使用适配器类,我们能够在不修改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

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

会话如何劫持工作,如何在PHP中减轻它? 会话如何劫持工作,如何在PHP中减轻它? Apr 06, 2025 am 12:02 AM

会话劫持可以通过以下步骤实现:1.获取会话ID,2.使用会话ID,3.保持会话活跃。在PHP中防范会话劫持的方法包括:1.使用session_regenerate_id()函数重新生成会话ID,2.通过数据库存储会话数据,3.确保所有会话数据通过HTTPS传输。

描述扎实的原则及其如何应用于PHP的开发。 描述扎实的原则及其如何应用于PHP的开发。 Apr 03, 2025 am 12:04 AM

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

PHP 8.1中的枚举(枚举)是什么? PHP 8.1中的枚举(枚举)是什么? Apr 03, 2025 am 12:05 AM

PHP8.1中的枚举功能通过定义命名常量增强了代码的清晰度和类型安全性。1)枚举可以是整数、字符串或对象,提高了代码可读性和类型安全性。2)枚举基于类,支持面向对象特性,如遍历和反射。3)枚举可用于比较和赋值,确保类型安全。4)枚举支持添加方法,实现复杂逻辑。5)严格类型检查和错误处理可避免常见错误。6)枚举减少魔法值,提升可维护性,但需注意性能优化。

在PHPStorm中如何进行CLI模式的调试? 在PHPStorm中如何进行CLI模式的调试? Apr 01, 2025 pm 02:57 PM

在PHPStorm中如何进行CLI模式的调试?在使用PHPStorm进行开发时,有时我们需要在命令行界面(CLI)模式下调试PHP�...

如何在系统重启后自动设置unixsocket的权限? 如何在系统重启后自动设置unixsocket的权限? Mar 31, 2025 pm 11:54 PM

如何在系统重启后自动设置unixsocket的权限每次系统重启后,我们都需要执行以下命令来修改unixsocket的权限:sudo...

如何用PHP的cURL库发送包含JSON数据的POST请求? 如何用PHP的cURL库发送包含JSON数据的POST请求? Apr 01, 2025 pm 03:12 PM

使用PHP的cURL库发送JSON数据在PHP开发中,经常需要与外部API进行交互,其中一种常见的方式是使用cURL库发送POST�...

See all articles