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

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
您如何防止与会议有关的跨站点脚本(XSS)攻击?您如何防止与会议有关的跨站点脚本(XSS)攻击?Apr 23, 2025 am 12:16 AM

要保护应用免受与会话相关的XSS攻击,需采取以下措施:1.设置HttpOnly和Secure标志保护会话cookie。2.对所有用户输入进行输出编码。3.实施内容安全策略(CSP)限制脚本来源。通过这些策略,可以有效防护会话相关的XSS攻击,确保用户数据安全。

您如何优化PHP会话性能?您如何优化PHP会话性能?Apr 23, 2025 am 12:13 AM

优化PHP会话性能的方法包括:1.延迟会话启动,2.使用数据库存储会话,3.压缩会话数据,4.管理会话生命周期,5.实现会话共享。这些策略能显着提升应用在高并发环境下的效率。

什么是session.gc_maxlifetime配置设置?什么是session.gc_maxlifetime配置设置?Apr 23, 2025 am 12:10 AM

thesession.gc_maxlifetimesettinginphpdeterminesthelifespanofsessiondata,setInSeconds.1)它'sconfiguredinphp.iniorviaini_set().2)abalanceIsiseededeedeedeedeedeedeedto to to avoidperformance andununununununexpectedLogOgouts.3)

您如何在PHP中配置会话名?您如何在PHP中配置会话名?Apr 23, 2025 am 12:08 AM

在PHP中,可以使用session_name()函数配置会话名称。具体步骤如下:1.使用session_name()函数设置会话名称,例如session_name("my_session")。2.在设置会话名称后,调用session_start()启动会话。配置会话名称可以避免多应用间的会话数据冲突,并增强安全性,但需注意会话名称的唯一性、安全性、长度和设置时机。

您应该多久再生一次会话ID?您应该多久再生一次会话ID?Apr 23, 2025 am 12:03 AM

会话ID应在登录时、敏感操作前和每30分钟定期重新生成。1.登录时重新生成会话ID可防会话固定攻击。2.敏感操作前重新生成提高安全性。3.定期重新生成降低长期利用风险,但需权衡用户体验。

如何在PHP中设置会话cookie参数?如何在PHP中设置会话cookie参数?Apr 22, 2025 pm 05:33 PM

在PHP中设置会话cookie参数可以通过session_set_cookie_params()函数实现。1)使用该函数设置参数,如过期时间、路径、域名、安全标志等;2)调用session_start()使参数生效;3)根据需求动态调整参数,如用户登录状态;4)注意设置secure和httponly标志以提升安全性。

在PHP中使用会议的主要目的是什么?在PHP中使用会议的主要目的是什么?Apr 22, 2025 pm 05:25 PM

在PHP中使用会话的主要目的是维护用户在不同页面之间的状态。1)会话通过session_start()函数启动,创建唯一会话ID并存储在用户cookie中。2)会话数据保存在服务器上,允许在不同请求间传递数据,如登录状态和购物车内容。

您如何在子域中分享会议?您如何在子域中分享会议?Apr 22, 2025 pm 05:21 PM

如何在子域名间共享会话?通过设置通用域名的会话cookie实现。1.在服务器端设置会话cookie的域为.example.com。2.选择合适的会话存储方式,如内存、数据库或分布式缓存。3.通过cookie传递会话ID,服务器根据ID检索和更新会话数据。

See all articles

热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

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

热工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版