首页 后端开发 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工具

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

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)

热门话题

Laravel 教程
1601
29
PHP教程
1502
276
PHP变量范围解释了 PHP变量范围解释了 Jul 17, 2025 am 04:16 AM

PHP变量作用域常见问题及解决方法包括:1.函数内部无法访问全局变量,需使用global关键字或参数传入;2.静态变量用static声明,只初始化一次并在多次调用间保持值;3.超全局变量如$_GET、$_POST可在任何作用域直接使用,但需注意安全过滤;4.匿名函数需通过use关键字引入父作用域变量,修改外部变量则需传递引用。掌握这些规则有助于避免错误并提升代码稳定性。

如何在PHP中牢固地处理文件上传? 如何在PHP中牢固地处理文件上传? Jul 08, 2025 am 02:37 AM

要安全处理PHP文件上传需验证来源与类型、控制文件名与路径、设置服务器限制并二次处理媒体文件。1.验证上传来源通过token防止CSRF并通过finfo_file检测真实MIME类型使用白名单控制;2.重命名文件为随机字符串并根据检测类型决定扩展名存储至非Web目录;3.PHP配置限制上传大小及临时目录Nginx/Apache禁止访问上传目录;4.GD库重新保存图片清除潜在恶意数据。

在PHP中评论代码 在PHP中评论代码 Jul 18, 2025 am 04:57 AM

PHP注释代码常用方法有三种:1.单行注释用//或#屏蔽一行代码,推荐使用//;2.多行注释用/.../包裹代码块,不可嵌套但可跨行;3.组合技巧注释如用/if(){}/控制逻辑块,或配合编辑器快捷键提升效率,使用时需注意闭合符号和避免嵌套。

发电机如何在PHP中工作? 发电机如何在PHP中工作? Jul 11, 2025 am 03:12 AM

AgeneratorinPHPisamemory-efficientwaytoiterateoverlargedatasetsbyyieldingvaluesoneatatimeinsteadofreturningthemallatonce.1.Generatorsusetheyieldkeywordtoproducevaluesondemand,reducingmemoryusage.2.Theyareusefulforhandlingbigloops,readinglargefiles,or

撰写PHP评论的提示 撰写PHP评论的提示 Jul 18, 2025 am 04:51 AM

写好PHP注释的关键在于明确目的与规范,注释应解释“为什么”而非“做了什么”,避免冗余或过于简单。1.使用统一格式,如docblock(/*/)用于类、方法说明,提升可读性与工具兼容性;2.强调逻辑背后的原因,如说明为何需手动输出JS跳转;3.在复杂代码前添加总览性说明,分步骤描述流程,帮助理解整体思路;4.合理使用TODO和FIXME标记待办事项与问题,便于后续追踪与协作。好的注释能降低沟通成本,提升代码维护效率。

学习PHP:初学者指南 学习PHP:初学者指南 Jul 18, 2025 am 04:54 AM

易于效率,启动启动tingupalocalserverenverenvirestoolslikexamppandacodeeditorlikevscode.1)installxamppforapache,mysql,andphp.2)uscodeeditorforsyntaxssupport.3)

如何通过php中的索引访问字符串中的字符 如何通过php中的索引访问字符串中的字符 Jul 12, 2025 am 03:15 AM

在PHP中获取字符串特定索引字符可用方括号或花括号,但推荐方括号;索引从0开始,超出范围访问返回空值,不可赋值;处理多字节字符需用mb_substr。例如:$str="hello";echo$str[0];输出h;而中文等字符需用mb_substr($str,1,1)获取正确结果;实际应用中循环访问前应检查字符串长度,动态字符串需验证有效性,多语言项目建议统一使用多字节安全函数。

快速PHP安装教程 快速PHP安装教程 Jul 18, 2025 am 04:52 AM

ToinstallPHPquickly,useXAMPPonWindowsorHomebrewonmacOS.1.OnWindows,downloadandinstallXAMPP,selectcomponents,startApache,andplacefilesinhtdocs.2.Alternatively,manuallyinstallPHPfromphp.netandsetupaserverlikeApache.3.OnmacOS,installHomebrew,thenrun'bre

See all articles