Points de base
log()
courante qui peut recevoir tous les niveaux de gravité. Sa conception est de résoudre le problème de l'incompatibilité de l'implémentation des logarithmes. AbstractLogger
fournie dans la bibliothèque PSR / log. Dans le développement de PHP, la journalisation est l'une des tâches les plus courantes. Nous utilisons des journaux pour suivre les messages d'erreur, enregistrer des événements importants et déboguer les problèmes de code. Dans n'importe quel projet PHP, le code peut être rempli d'appels aux bibliothèques de journaux qui gèrent ces opérations pour nous. Malheureusement, les appels aux bibliothèques de journaux sont dispersés dans tout le code, ce qui rend le code dépend de la disponibilité de la bibliothèque, ce qui est clairement contraire au principe de l'inversion de dépendance. Même si nous utilisons l'injection de dépendance pour permettre à nos objets d'accéder à la bibliothèque de journaux, la différence entre les bibliothèques de journaux signifie que les commutations entre eux peuvent être difficiles et longs, nécessitant une refactorisation majeure de la bibliothèque de code entière. Pour améliorer la compatibilité entre les bibliothèques de journaux, l'équipe PHP-Fig a récemment publié PSR-3, une interface d'objet logarithmique commune. Dans cet article, je vais discuter de la façon dont l'interface de journal définie par PSR-3 nous permet d'écrire du code réutilisable qui ne dépend d'une implémentation de journal particulière.
PSR-3 Démarrage rapide
Avant de comprendre comment PSR-3 rend notre code plus réutilisable, il est nécessaire de comprendre ce qu'est le PSR-3. Si vous connaissez déjà PSR-3, vous pouvez ignorer cette section. Le noyau de la spécification est l'interface pour log les objets. Cette interface révèle huit façons de gérer les messages de différents niveaux de gravité et une méthode courante log()
qui peut accepter les niveaux de gravité. Les huit niveaux de gravité soutenus par PSR-3 sont basés sur RFC 5424, comme décrit ci-dessous:
emergency
- Le système ne peut pas être utilisé alert
- L'action est requise critical
- situation grave error
- Erreurs qui n'ont pas besoin d'attention immédiate mais doivent être surveillées warning
- un événement inhabituel ou indésirable, mais pas une erreur notice
- Événements normaux mais importants info
- Événements intéressants debug
- Détails pour le débogage Chaque méthode de journal accepte un message qui doit être une chaîne ou un objet avec une méthode __toString()
. Les paramètres supplémentaires acceptent un tableau qui peut fournir des informations de contexte pour les messages de journal. Une description complète de ces méthodes et paramètres peut être trouvée dans la spécification PSR-3.
Obtenez un fichier psr-3
Obtenir les fichiers dont vous avez besoin pour utiliser PSR-3 est facile - vous pouvez les trouver dans le référentiel PSR / Log GitHub. Vous pouvez également utiliser Composer pour obtenir ces fichiers de Packagist. Voici un exemple de fichier A composer.json
pour récupérer les fichiers PSR / journaux:
{ "require": { "psr/log": "dev-master" } }
Comment limiter la réutilisation du code de la journalisation
PHP a de nombreuses bibliothèques de journaux différentes, chacune avec sa propre façon de collecter et d'enregistrer des données. Bien qu'ils aient des points communs, chaque bibliothèque a son propre ensemble unique de méthodes de journalisation. Cela signifie que la commutation entre les journaux peut être difficile et nécessite souvent de modifier le code où vous utilisez la journalisation. Cela fonctionne à contraire au principe solide de la réutilisation du code et de la conception orientée objet. La situation à laquelle nous sommes confrontés est que déclarer les dépendances sur des bibliothèques de journaux spécifiques ou éviter complètement la journalisation. Pour illustrer ce problème plus clairement, un exemple spécifique est nécessaire. Supposons que nous créons un simple objet Mailer pour gérer l'envoi d'e-mails. Nous voulons que Mailer enregistre un message chaque fois que nous envoyons un e-mail, et nous avons décidé d'utiliser l'excellente bibliothèque Monologue pour répondre à nos besoins de journalisation.
<?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"); } }
Nous pouvons utiliser cette classe avec le code suivant:
<?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");
L'exécution de ce code créera une nouvelle entrée dans le fichier mail.log
, enregistrant l'e-mail envoyé. À ce stade, nous pourrions penser que nous avons écrit un objet Mailer réutilisable. Nous utilisons l'injection de dépendance pour rendre l'enregistreur disponible pour Mailer, afin que nous puissions échanger différentes configurations d'enregistrement sans toucher à notre code Mailer. Il semble que nous ayons réussi le principe solide et évité de créer des dépendances dures. Mais supposons que nous voulons réutiliser la classe Mailer dans différents projets en utilisant Analog pour gérer les interactions de journalisation. Maintenant, nous avons un problème car Analog n'a pas de méthode addInfo()
. Pour enregistrer les messages au niveau de l'information à l'aide de Analog, nous appelons Analog::log($message, Analog::INFO)
. Nous pouvons modifier la classe Mailer pour utiliser la méthode analogique comme indiqué ci-dessous.
<?php namespace Email; class Mailer { public function sendEmail($emailAddress) { // 发送电子邮件的代码... // 记录消息 Analog::log("Email sent to $emailAddress", Analog::INFO); } }
Nous pouvons utiliser la classe Mailer mise à jour avec le code suivant:
{ "require": { "psr/log": "dev-master" } }
Bien que cela fonctionnera, il est loin d'être idéal. Nous avons rencontré la dépendance de Mailer à l'égard d'une implémentation de journalisation spécifique, ce qui nécessite de modifier la classe lors de l'introduction d'un nouvel enregistreur. Cela rend la classe moins réutilisable et nous oblige à choisir entre s'appuyer sur la disponibilité d'un enregistreur particulier ou l'abandon de la journalisation dans la classe.
Utilisez PSR-3 pour éviter les dépendances en journaliste
Comme l'explique Alejandro Gervasio dans son excellent article sur le sujet, le principe de l'inversion de dépendance nous dit que nous devons compter sur l'abstraction plutôt que sur des implémentations concrètes. Dans le cas de l'exploitation forestière, notre problème actuel a été l'absence d'une abstraction appropriée sur laquelle on peut s'appuyer. C'est là que le PSR-3 entre en jeu. Le PSR-3 est conçu pour surmonter l'incompatibilité de la mise en œuvre de la journalisation en fournissant une interface commune pour l'enregistreur (correctement nommé LoggerInterface
). En fournissant une interface qui n'est pas liée à une implémentation spécifique, PSR-3 nous permet d'éviter de compter sur un enregistreur spécifique - nous pouvons plutôt taper une invite LoggerInterface
pour obtenir un enregistreur conforme à PSR-3. J'ai mis à jour la classe Mailer suivante pour le démontrer:
<?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"); } }
a été modifié pour accepter l'implémenteur LoggerInterface
, et la méthode sendEmail()
appelle désormais la méthode info()
spécifiée dans PSR-3. Monolog est déjà conforme PSR-3, et Analog fournit un objet wrapper qui implémente LoggerInterface
, nous pouvons donc maintenant utiliser ces deux bûcherons sans modifier la classe Mailer. Voici comment appeler ce cours à l'aide de 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");
et utilisez un analogique:
<?php namespace Email; class Mailer { public function sendEmail($emailAddress) { // 发送电子邮件的代码... // 记录消息 Analog::log("Email sent to $emailAddress", Analog::INFO); } }
Maintenant, nous pouvons utiliser notre objet Mailer avec une bibliothèque sans modifier la classe Mailer ou modifier la façon dont nous l'utilisons.
Utilisez le mode adaptateur pour les journalistes qui ne prennent pas en charge PSR-3
Jusqu'à présent, nous avons réussi à découpler l'objet Mailer à partir de toute implémentation de journalisation spécifique via l'implémentateur demandant LoggerInterface
. Mais qu'en est-il des journalistes qui n'ont pas encore été ajoutés pour le support PSR-3? Par exemple, la populaire bibliothèque Klogger n'a pas été mise à jour depuis un certain temps et est actuellement incompatible avec PSR-3. Heureusement, nous pouvons facilement cartographier les méthodes exposées par Klogger à celles définies dans LoggerInterface
en tirant parti du motif de l'adaptateur. Les fichiers pris en charge dans le référentiel PSR / Log nous permettent de créer facilement des classes d'adaptateur en fournissant une classe AbstractLogger
que nous pouvons étendre. Une classe abstraite transmet simplement huit méthodes de journal spécifiques au niveau défini dans LoggerInterface
à une méthode commun log()
. En étendant la classe AbstractLogger
et en définissant notre propre méthode log()
, nous pouvons facilement créer des adaptateurs conformes PSR-3 aux journalistes qui ne prennent pas nativement le PSR-3. Je vais le démontrer ci-dessous en créant un adaptateur simple pour Klogger:
{ "require": { "psr/log": "dev-master" } }
log()
mappe simplement la méthode LoggerInterface
à la méthode Klogger respective, et le klogger gère l'activité de journalisation réelle. En emballant la classe Klogger de cette façon, nous pouvons l'utiliser sans casser le contrat LoggerInterface
. Nous pouvons maintenant utiliser l'adaptateur Klogger avec la classe 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"); } }
Avec la classe d'adaptateur, nous pouvons utiliser Klogger sans modifier la classe Mailer et adhérer toujours à LoggerInterface
. Klogger n'accepte pas le deuxième paramètre des messages de niveau de débogage, il ne se conforme donc pas pleinement au PSR-3 même avec un adaptateur. L'extension de Klogger pour le rendre entièrement compatible avec le PSR-3 serait une tâche triviale, mais cela dépasse le cadre de cet article. Cependant, il est sûr de dire que l'utilisation de notre classe d'adaptateur nous rend très près d'être entièrement conformes au PSR-3 et nous permet d'utiliser LoggerInterface
avec la classe Klogger.
Conclusion
Dans cet article, nous avons appris à utiliser PSR-3 pour nous aider à rédiger du code sans enregistrement qui ne dépend pas d'une implémentation de journalisation spécifique. De nombreux projets PHP majeurs ont ajouté un soutien pour PSR-3, notamment Monolog, Symfony et Mustache.php, ainsi que d'autres projets bien connus comme Drupal discutent de la meilleure façon de l'intégrer. Étant donné que le PSR-3 réduit les obstacles à la réutilisation du code, nous devrions voir davantage de bibliothèques et de frameworks utiliser correctement la journalisation pour fournir des informations utiles aux développeurs. PSR-3 affectera-t-il la façon dont vous utilisez la journalisation dans votre application? Veuillez nous faire savoir dans la section des commentaires ci-dessous.
(image de Fotolia)
(La partie FAQ de la journalisation PSR-3 est omise ici en raison des limitations de l'espace. Il peut être ajouté au besoin.)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!