Core points
- PSR-3, a common log object interface, allows developers to write reusable code without relying on any specific log implementation, thereby improving compatibility between different log libraries in PHP. The
- PSR-3 interface provides eight methods to handle messages of different severity levels, and a common
log()
method that can receive any severity levels. Its design is to solve the problem of log implementation incompatibility. - Although PSR-3 has many benefits, some log libraries do not support it natively. However, developers can create PSR-3 compliant adapters by leveraging the adapter mode and extending the
AbstractLogger
class provided in the Psr/Log library. - Many major PHP projects, including Monolog, Symfony, and Mustache.php, have added support for PSR-3. As it reduces the barriers to code reuse, more libraries and frameworks are expected to use logging correctly, providing useful information for developers.
In PHP development, logging is one of the most common tasks. We use logs to track error messages, log important events, and debug code issues. In any PHP project, the code may be filled with calls to log libraries that handle these operations for us. Unfortunately, calls to log libraries are scattered throughout the code, which makes the code depend on the availability of the library, which is clearly contrary to the principle of dependency inversion. Even if we use dependency injection to let our objects access the log library, the difference between log libraries means switching between them can be difficult and time-consuming, requiring a major refactoring of the entire code library. To improve compatibility between log libraries, the PHP-FIG team recently released PSR-3, a common log object interface. In this article, I will discuss how the PSR-3 defined log interface allows us to write reusable code that does not depend on any particular log implementation.
PSR-3 Quick Start
Before we understand how PSR-3 makes our code more reusable, it is necessary to understand what PSR-3 is. If you are already familiar with PSR-3, you can skip this section. The core of the specification is the interface to log objects. This interface discloses eight ways to handle messages of different severity levels, and a common log()
method that can accept any severity levels. The eight severity levels supported by PSR-3 are based on RFC 5424, as described below:
-
emergency
– The system cannot be used -
alert
– Action is required -
critical
– Serious situation -
error
– Errors that do not need immediate attention but should be monitored -
warning
– An unusual or undesirable event, but not an error -
notice
– Normal but important events -
info
– Interesting Events -
debug
– Details for debugging
Each log method accepts a message that must be a string or an object with a __toString()
method. Additional parameters accept an array that can provide context information for log messages. A complete description of these methods and parameters can be found in the PSR-3 specification.
Get PSR-3 file
Getting the files you need to use PSR-3 is easy - you can find them in the Psr/Log GitHub repository. You can also use Composer to get these files from Packagist. Here is an example of a composer.json
file for retrieving Psr/Log files:
{ "require": { "psr/log": "dev-master" } }
How to limit code reuse of logging
PHP has many different log libraries, each with its own way of collecting and recording data. While they have some commonalities, each library has its own unique set of logging methods. This means switching between logs can be challenging, and often requires changing the code where you use logging. This runs contrary to the SOLID principle of code reuse and object-oriented design. The situation we face is that either declare dependencies on specific log libraries or avoid logging altogether. To illustrate this issue more clearly, a specific example is needed. Suppose we are creating a simple Mailer object to handle sending emails. We want Mailer to log a message every time we send an email, and we decided to use the excellent Monolog library to handle our logging needs.
<?php namespace Email; class Mailer { private $logger; public function __construct($logger) { $this->logger = $logger; } public function sendEmail($emailAddress) { // 發(fā)送電子郵件的代碼... // 記錄消息 $this->logger->addInfo("Email sent to $emailAddress"); } }
We can use this class with the following code:
<?php // 創(chuàng)建一個Monolog對象 $logger = new Monolog\Logger("Mail"); $logger->pushHandler(new Monolog\Handler\StreamHandler("mail.log")); // 創(chuàng)建郵件發(fā)送器并發(fā)送電子郵件 $mailer = new Email\Mailer($logger); $mailer->sendEmail("email@example.com");
Running this code will create a new entry in the mail.log
file, recording the email sent. At this point, we might think that we have written a reusable Mailer object. We use dependency injection to make the logger available for Mailer, so we can swap different logger configurations without touching our Mailer code. It looks like we have successfully followed the SOLID principle and avoided creating any hard dependencies. But suppose we want to reuse the Mailer class in different projects using Analog to handle logging interactions. Now we have a problem because Analog does not have a addInfo()
method. To record information-level messages using Analog, we call Analog::log($message, Analog::INFO)
. We can modify the Mailer class to use the Analog method as shown below.
<?php namespace Email; class Mailer { public function sendEmail($emailAddress) { // 發(fā)送電子郵件的代碼... // 記錄消息 Analog::log("Email sent to $emailAddress", Analog::INFO); } }
We can use the updated Mailer class with the following code:
{ "require": { "psr/log": "dev-master" } }
While this will work, it is far from ideal. We encountered Mailer's dependency on a specific logging implementation, which requires changing the class when introducing a new logger. This makes the class less reusable and forces us to choose between relying on the availability of a particular logger or abandoning logging in the class altogether.
Use PSR-3 to avoid logger dependencies
As Alejandro Gervasio explains in his excellent article on the topic, the principle of dependency inversion tells us that we should rely on abstraction rather than concrete implementations. In the case of logging, our current problem has been the lack of a suitable abstraction that can be relied on. This is where PSR-3 comes into play. PSR-3 is designed to overcome the incompatibility of logging implementation by providing a common interface for the logger (properly named LoggerInterface
). By providing an interface that is not bound to any specific implementation, PSR-3 allows us to avoid relying on a specific logger - we can instead type prompt for LoggerInterface
to get a PSR-3-compliant logger. I've updated the following Mailer class to demonstrate this:
<?php namespace Email; class Mailer { private $logger; public function __construct($logger) { $this->logger = $logger; } public function sendEmail($emailAddress) { // 發(fā)送電子郵件的代碼... // 記錄消息 $this->logger->addInfo("Email sent to $emailAddress"); } }The
constructor has been modified to accept the LoggerInterface
implementer, and the sendEmail()
method now calls the info()
method specified in PSR-3. Monolog is already PSR-3 compliant, and Analog provides a wrapper object that implements LoggerInterface
, so we can now use these two loggers without modifying the Mailer class. Here is how to call this class using Monolog:
<?php // 創(chuàng)建一個Monolog對象 $logger = new Monolog\Logger("Mail"); $logger->pushHandler(new Monolog\Handler\StreamHandler("mail.log")); // 創(chuàng)建郵件發(fā)送器并發(fā)送電子郵件 $mailer = new Email\Mailer($logger); $mailer->sendEmail("email@example.com");
and use Analog:
<?php namespace Email; class Mailer { public function sendEmail($emailAddress) { // 發(fā)送電子郵件的代碼... // 記錄消息 Analog::log("Email sent to $emailAddress", Analog::INFO); } }
Now we are able to use our Mailer object with any library without editing the Mailer class or changing the way we use it.
Use adapter mode for loggers that do not support PSR-3
So far, we have successfully decoupled the Mailer object from any specific logging implementation through the implementer requesting LoggerInterface
. But what about those loggers that have not yet been added for PSR-3 support? For example, the popular KLogger library has not been updated for a while and is currently incompatible with PSR-3. Fortunately, we can easily map the methods exposed by KLogger to those defined in LoggerInterface
by leveraging the adapter pattern. Supported files in the Psr/Log repository enable us to easily create adapter classes by providing a AbstractLogger
class that we can extend. An abstract class simply forwards eight level-specific log methods defined in LoggerInterface
to a common log()
method. By extending the AbstractLogger
class and defining our own log()
method, we can easily create PSR-3-compliant adapters for loggers that do not natively support PSR-3. I'll demonstrate this below by creating a simple adapter for KLogger:
{ "require": { "psr/log": "dev-master" } }The
log()
method simply maps the LoggerInterface
method to the respective KLogger method, and the KLogger handles the actual logging activity. By wrapping the KLogger class this way, we are able to use it without breaking the LoggerInterface
contract. We can now use the KLogger adapter with the Mailer class:
<?php namespace Email; class Mailer { private $logger; public function __construct($logger) { $this->logger = $logger; } public function sendEmail($emailAddress) { // 發(fā)送電子郵件的代碼... // 記錄消息 $this->logger->addInfo("Email sent to $emailAddress"); } }
With the adapter class, we are able to use KLogger without modifying the Mailer class and still adhere to LoggerInterface
. KLogger does not accept the second parameter of debug level messages, so it does not fully comply with PSR-3 even with an adapter. Extending KLogger to make it fully compatible with PSR-3 would be a trivial task, but that's beyond the scope of this article. However, it is safe to say that using our adapter class makes us very close to being fully PSR-3 compliant and allows us to use LoggerInterface
with the KLogger class.
Conclusion
In this article, we have learned how to use PSR-3 to help us write logger-free code that does not depend on a specific logging implementation. Many major PHP projects have added support for PSR-3, including Monolog, Symfony, and Mustache.php, as well as other well-known projects like Drupal are discussing how to best integrate it. Since PSR-3 reduces the barriers to code reuse, we should see more libraries and frameworks correctly use logging to provide useful information for developers. Will PSR-3 affect how you use logging in your application? Please let us know in the comments section below.
(Picture from Fotolia)
(The FAQ part of PSR-3 logging is omitted here due to space limitations. It can be added as needed.)
The above is the detailed content of PHP Master | Logging with PSR-3 to Improve Reusability. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

ToversionaPHP-basedAPIeffectively,useURL-basedversioningforclarityandeaseofrouting,separateversionedcodetoavoidconflicts,deprecateoldversionswithclearcommunication,andconsidercustomheadersonlywhennecessary.StartbyplacingtheversionintheURL(e.g.,/api/v

TosecurelyhandleauthenticationandauthorizationinPHP,followthesesteps:1.Alwayshashpasswordswithpassword_hash()andverifyusingpassword_verify(),usepreparedstatementstopreventSQLinjection,andstoreuserdatain$_SESSIONafterlogin.2.Implementrole-basedaccessc

PHPdoesnothaveabuilt-inWeakMapbutoffersWeakReferenceforsimilarfunctionality.1.WeakReferenceallowsholdingreferenceswithoutpreventinggarbagecollection.2.Itisusefulforcaching,eventlisteners,andmetadatawithoutaffectingobjectlifecycles.3.YoucansimulateaWe

Proceduralandobject-orientedprogramming(OOP)inPHPdiffersignificantlyinstructure,reusability,anddatahandling.1.Proceduralprogrammingusesfunctionsorganizedsequentially,suitableforsmallscripts.2.OOPorganizescodeintoclassesandobjects,modelingreal-worlden

To safely handle file uploads in PHP, the core is to verify file types, rename files, and restrict permissions. 1. Use finfo_file() to check the real MIME type, and only specific types such as image/jpeg are allowed; 2. Use uniqid() to generate random file names and store them in non-Web root directory; 3. Limit file size through php.ini and HTML forms, and set directory permissions to 0755; 4. Use ClamAV to scan malware to enhance security. These steps effectively prevent security vulnerabilities and ensure that the file upload process is safe and reliable.

Yes, PHP can interact with NoSQL databases like MongoDB and Redis through specific extensions or libraries. First, use the MongoDBPHP driver (installed through PECL or Composer) to create client instances and operate databases and collections, supporting insertion, query, aggregation and other operations; second, use the Predis library or phpredis extension to connect to Redis, perform key-value settings and acquisitions, and recommend phpredis for high-performance scenarios, while Predis is convenient for rapid deployment; both are suitable for production environments and are well-documented.

In PHP, the main difference between == and == is the strictness of type checking. ==Type conversion will be performed before comparison, for example, 5=="5" returns true, and ===Request that the value and type are the same before true will be returned, for example, 5==="5" returns false. In usage scenarios, === is more secure and should be used first, and == is only used when type conversion is required.

TostaycurrentwithPHPdevelopmentsandbestpractices,followkeynewssourceslikePHP.netandPHPWeekly,engagewithcommunitiesonforumsandconferences,keeptoolingupdatedandgraduallyadoptnewfeatures,andreadorcontributetoopensourceprojects.First,followreliablesource
