5. diel - Štandardy jazyka PHP - Implementácia PSR-3
V minulej lekcii, Štandardy jazyka PHP - PSR-3 a špecifikácie loggeru , sme si predstavili základné myšlienky špecifikácia PSR-3, ktorá sa zaoberá logovaním. Dnešná lekcia je venovaná jej implementáciu.
Balíček
Rozhrania a opísané triedy sú rovnako ako príslušnej triedy výnimiek a testovacie prostredie poskytnuté ako časť balíčka psr / log pre kontrolu vašej implementácie. Nižšie je rozhranie s českými komentármi.
Rozhranie Psr \ Log \ LoggerInterface
<?php namespace Psr\Log; /** * Popisuje instanci loggeru * * Zpráva MUSÍ být string nebo objekt, který implementuje __toString(). * * Zpráva MŮŽE obsahovat zástupné identifikátory ve formě {foo}, kde foo * bude nahrazeno kontextovými daty pod klíčem "foo". * * Kontextové pole může obsahovat libovolná data, jediným předpokladem * implementátora je, že pokud je předávána instance Exception za účelem * produkování stack trace, MUSÍ být v klíči jménem "exception". * * Pro plnou specifikaci rozhraní navštivte * https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md */ interface LoggerInterface { /** * Systém je nepoužitelný. * * @param string $message * @param array $context * @return null */ public function emergency($message, array $context = array()); /** * Je nutné ihned provést akci. * * Příklad: Celá stránka je mimo provoz, databáze nedostupná a podobně. Metoda by * měla spustit SMS upozornění a vzbudit vás. * * @param string $message * @param array $context * @return null */ public function alert($message, array $context = array()); /** * Kritické podmínky. * * Příklad: Komponenta aplikace je nedostupná, neočekávaná výjimka. * * @param string $message * @param array $context * @return null */ public function critical($message, array $context = array()); /** * Běhové chyby, které nevyžadují okamžitou akci, ale měly by být typicky * logovány a sledovány. * * @param string $message * @param array $context * @return null */ public function error($message, array $context = array()); /** * Výjimečné události, které nejsou chybami. * * Příklad: Použití zastaralého API, nesprávné použití API, nevhodné věci, * které nemusí být nutně špatně. * * @param string $message * @param array $context * @return null */ public function warning($message, array $context = array()); /** * Normální, ale podstatné události. * * @param string $message * @param array $context * @return null */ public function notice($message, array $context = array()); /** * Zajímavé události. * * Příklad: Uživatelská přihlášení, SQL logy. * * @param string $message * @param array $context * @return null */ public function info($message, array $context = array()); /** * Detailní ladící informace. * * @param string $message * @param array $context * @return null */ public function debug($message, array $context = array()); /** * Zaloguje s libovolnou úrovní. * * @param mixed $level * @param string $message * @param array $context * @return null */ public function log($level, $message, array $context = array()); }
Rozhranie Psr \ Log \ LoggerAwareInterface
<?php namespace Psr\Log; /** * Popisuje instanci, která používá logger */ interface LoggerAwareInterface { /** * Nastaví objektu instanci loggeru * * @param LoggerInterface $logger * @return null */ public function setLogger(LoggerInterface $logger); }
Trieda Psr \ Log \ LogLevel
<?php namespace Psr\Log; /** * Popisuje logovací úrovně */ class LogLevel { const EMERGENCY = 'emergency'; const ALERT = 'alert'; const CRITICAL = 'critical'; const ERROR = 'error'; const WARNING = 'warning'; const NOTICE = 'notice'; const INFO = 'info'; const DEBUG = 'debug'; }
Ukážková implementácia
Preklad špecifikácia je síce pekná vec, však chcelo by to nejaký konkrétny príklad, že? Vytvorme si jednoduchý logger, ktorý zodpovedá špecifikácii PSR-3 a následne si ukážme aj jeho použitie. V kóde nižšie použijeme rovno aj PSR-4, ktorú máme v pláne na nabudúce. Tá udáva akým spôsobom pomenovávať menné priestory, implementovať autoloader a ako členiť triedy do priečinkov. Túto časť kódu teda plne pochytíte až nabudúce.
Ako prvý si založíme nový projekt. Vytvoríme si v ňom zložku vendor, v nej podpriečinok Psr a v nej podpriečinok Log. Práve sem vložíme 3 súbory s vyššie uvedenými zdrojovými kódmi: LoggerAwareInterface.php, LoggerInterface.php, LogLevel.php. Vendor je zložka pre triedy, ktorá sa ďalej vetví podľa ich výrobcov (od toho názov vendor). Rozhranie máme teda pripravená, teraz je implementujeme.
V priečinku vendor vytvoríme podpriečinok ItNetwork (pretože ItNetwork je ich výrobca), kam pridáme 2 triedy:
Logger.php
Logger je samotná implementácia nášho loggeru. Z kódu som odstránil komentáre, aby sa článok kompaktnejší, okomentovanou verziu si môžete stiahnuť v prílohe. Kód je extrémne jednoduchý, každá z 8mi metód zatiaľ len zapisuje riadku do textového súboru. Pripísania riadky je atomická operácie, takže sa nemusíme starať o lockování. Metóda log () potom podľa typu úrovne spustí danú metódu. Tie kritickejší metódy by sa v praxi doplnili o nejakej odosielanie emailov, SMSiek, spúšťanie sirén a podobne
namespace ItNetwork; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; class Logger implements LoggerInterface { const FILENAME = 'errors.log'; public function emergency($message, array $context = array()) { $this->appendLine(LogLevel::EMERGENCY, $message, $context); } public function alert($message, array $context = array()) { $this->appendLine(LogLevel::ALERT, $message, $context); } public function critical($message, array $context = array()) { $this->appendLine(LogLevel::CRITICAL, $message, $context); } public function error($message, array $context = array()) { $this->appendLine(LogLevel::ERROR, $message, $context); } public function warning($message, array $context = array()) { $this->appendLine(LogLevel::WARNING, $message, $context); } public function notice($message, array $context = array()) { $this->appendLine(LogLevel::NOTICE, $message, $context); } public function info($message, array $context = array()) { $this->appendLine(LogLevel::INFO, $message, $context); } public function debug($message, array $context = array()) { $this->appendLine(LogLevel::DEBUG, $message, $context); } private function interpolate($message, array $context = array()) { // vytvoří nahrazovací pole se závorkami okolo kontextových klíčů $replace = array(); foreach ($context as $key => $val) { $replace['{' . $key . '}'] = $val; } // interpoluje nahrazovací hodnoty do zprávy a vrátí je return strtr($message, $replace); } private function appendLine($level, $message, $context) { $message = $this->interpolate($message, $context); file_put_contents(self::FILENAME, $level . ': ' . $message . PHP_EOL, FILE_APPEND); } public function log($level, $message, array $context = array()) { switch ($level) { case LogLevel::EMERGENCY: $this->emergency($message, $context); break; case LogLevel::ALERT: $this->alert($message, $context); break; case LogLevel::CRITICAL: $this->critical($message, $context); break; case LogLevel::ERROR: $this->error($message, $context); break; case LogLevel::WARNING: $this->error($message, $context); break; case LogLevel::NOTICE: $this->notice($message, $context); break; case LogLevel::INFO: $this->info($message, $context); break; case LogLevel::DEBUG: $this->debug($message, $context); break; } } }
EmailSender.php
Následne vytvorme objekt, ktorý logger používa. Pôjde o jednoduchý kódový emailov, ktorý zaloguje notice ak sa email nepodarí odoslať. Objekt bude implementovať rozhranie LoggerAwareInterface.
namespace ItNetwork; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; class EmailSender implements LoggerAwareInterface { private $logger; public function send($address, $subject, $message, $from) { $header = "From: " . $from; $header .= "\nMIME-Version: 1.0\n"; $header .= "Content-Type: text/html; charset=\"utf-8\"\n"; if (!mb_send_mail($address, $subject, $message, $header)) $this->logger->notice('Email na adresu {address} se nepodařilo odeslat.', array('address' => $address)); } public function setLogger(LoggerInterface $logger) { $this->logger = $logger; } }
No a konečne do koreňového priečinka (nad vendor) pridáme index.php, kam umiestnime autoloader, vytvoríme Logger a EmailSender, EmailSenderu nastavíme Logger a pokúsime sa odoslať email na nejakú neexistujúcu adresu:
use ItNetwork\EmailSender; use ItNetwork\Logger; function autoloader($class) { $class = 'vendor\\' . $class; $path = str_replace('\\', '/', $class) . '.php'; if (!include($path)) throw new Exception('Autoloader Error'); // Vyhodíme výjimku, abychom zjistili kde nastala chyba } spl_autoload_register("autoloader"); $logger = new Logger(); $emailSender = new EmailSender(); $emailSender->setLogger($logger); $emailSender->send('neexistuje', 'Žádný', 'Ahoj, toto nikdy nebudeš číst.', '[email protected]');
Skript niekoľkokrát spustíme. Výsledkom je vytvorenie súboru errors.txt, ktorý má nasledujúci obsah:
Máme univerzálny logger, ktorý môžeme centrálne používať nielen zo svojich tried, ale dokonca ho budú vďaka rozhraniu Psr \ Log \ LoggerInterface vedieť používať aj komponenty tretích strán, ktoré ho nikdy nevideli
Budúci lekcie, Štandardy jazyka PHP - PSR-4 a autoloader , je venovaná špecifikáciu PSR-4, ktorá sa týka Autoloader.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 99x (6.64 kB)
Aplikácia je vrátane zdrojových kódov v jazyku PHP