Ha a WordPress rendszerünk életciklusa során arra adjuk a fejünket, hogy belenyúlunk a kódba, előfordulhat, hogy látni szeretnénk működés közben a program viselkedését, a változóink értékét, vagy, hogy egy bonyolult elágazás mely ágában köt ki a kódunk. Hova tovább hasznos lehet a konkrét hiba behatároláshoz, ha nem csak a weboldal látogatóinak, felhasználóinak szánt –kevésbé informatív, általános–üzeneteket látjuk a fejlesztéseinkből, mely általában csekély információ arra, hogy nekiinduljunk a hibakeresés rögös útvesztőjének.
Egy ’éles’ weboldalon pedig vajmi kevés esélyünk van arra, hogy kedvenc php-fejlesztő IDE-nket megnyitva töréspontokkal tűzdeljük tele kódot, és futás közben meg-megállva vizsgálódjunk hibák után kutatva.
Számtalan megbízható módszer létezik a hibák okának feltárására, kezdve a javascriptes konzolra kiíratós módszertől egészen a logokat adatbázisba mentő megoldásokon át, személyes kedvencem azonban a ’fájlba írós’ módszer. Ehhez szinte semmi másra nincs szükségünk, mint hogy a webtárhely FTP-jéhez hozzáférjünk, (akár egy FTP-kliens, akár a webes mondjuk cPanel segítségével) valamint a jó öreg fopen, fwrite és fclose függvénycsaládra. Ezt a módszert lehet központosítva is használni, a wp-content/plugins mappába helyezve a logoló osztályunkat, én azonban plugin-szinten szoktam hozzáadni a kódbázishoz, mivel így még könnyebben lehet akár minden egyes pluginhez egy külön mappát gyártani, melyben csak az őrá jellemző debuggolást találjuk. (Megj. : aki dolgozott már több tíz megás log fájlokkal, az talán értékelheti ezt a megoldást)
A kódrészlet, fő függvényünkkel tehát a következőképpen fog kinézni:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public static function _fecho( $log , $fileMode = "a" ) { $path = "/plugin-logs/log" ; $path .= date ( '_Ymd-Hi' ). ".txt" ; $myfile = fopen ( $path , $fileMode ) or die ( "Unable to open file!" ); fwrite( $myfile , self::get_log_time(). ":" . $log . "\n" ); fclose( $myfile ); } private static function get_log_time() { $t = microtime( true ); $micro = sprintf( "%06d" ,( $t - floor ( $t ) ) * 1000000 ); $d = new \DateTime( date ( 'Y-m-d H:i:s.' . $micro , $t ) ); return $d ->format( "Y-m-d H:i:s.u" ); } |
Mint látjuk, mindkét függvény statikus, ezáltal nincs szükség osztály-példányosításra. A get_log_time segéd-függvény csupán arra szolgál, hogy a fájlunkban kiíratott logokhoz egy pontos időbélyeg is tartozzon.
Amint látható fő _fecho függvényünkben megadunk egy alapértelmezett helyet a mappaszerkezeten belül, ahova elmentjük majd a log fájlokat, s mely útvonal akár paraméterként is beadható, vagy módosítható függvényen belülről.
Működése egyszerű: egyetlen egy paramétert vár a függvény, a $log változóban, melyet ki fogunk íratni a fájlba, a második paraméter – mint látható opcionális – alapértelmezett értékkel rendelkezik, s ezzel a fájlhoz illesztjük a tartalmat. Egy friss időbélyeg segítségével beleírjuk a debuggolni kívánt tartalmat, majd lezárjuk. Remélhetőleg az fopen, fwrite valamint az fclose függvények mindenki számára ismeretesek. A log mappánkban pedig szépen sorakoznak majd a log fájlok.

Apró egyszerűsítés, ha írunk az osztályunkhoz pár burkoló függvényt, így egyszerű és letisztult függvényhívásokat hajthatunk végre. A szöveg-formátum megadása egyéni ízlés kérdése, de helyezzük az olvashatóságot, átláthatóságot az előtérbe.
1 2 3 4 5 6 7 8 9 | function _log( $caller , $str ) { _l( '[ LOG ]: ' . $caller . ' : ' . $str ); } function _error( $caller , $str ) { _l( '[ ERROR ]: ' . $caller . ' : ' . $str ); } function _l( $str ) { Logger::_fecho( $str ); } |
A wordpress pluginünk kódjában pedig szintén egyszerű a meghívása, mindössze importálnunk kell a Logger osztályt, valamint a wrapper függvényeket.
1 2 | use function Logger\_log; use function Logger\_error; |
Egy-egy log fájl tartalma pedig tetszőlegesen:

A képek önmagukért beszélnek. Végezetül a teljes kód pár tíz sorban:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?php namespace Logger; define( 'PLUGIN_DEBUG' , true ); // This should be turned off, to silence logs. class Logger { /* Save the log output to a file, with timestamp. * * @param $log - The string to output in the file. * @param $fileMode - Whether to append or simply write to the file. */ public static function _fecho( $log , $fileMode = "a" ) { if ( PLUGIN_DEBUG ) { $path = "/plugin-logs/log" ; $path .= date ( '_Ymd-Hi' ). ".txt" ; $myfile = fopen ( $path , $fileMode ) or die ( "Unable to open file!" ); fwrite( $myfile , self::get_log_time(). ":" . $log . "\n" ); fclose( $myfile ); } } /* Get the time in milliseconds. */ private static function get_log_time() { $t = microtime( true ); $micro = sprintf( "%06d" ,( $t - floor ( $t ) ) * 1000000 ); $d = new \DateTime( date ( 'Y-m-d H:i:s.' . $micro , $t ) ); return $d ->format( "Y-m-d H:i:s.u" ); } } /* ~Logger */ function _log( $caller , $str ) { _l( '[ LOG ]: ' . $caller . ' : ' . $str ); } function _error( $caller , $str ) { _l( '[ ERROR ]: ' . $caller . ' : ' . $str ); } function _l( $str ) { Logger::_fecho( $str ); } //Logger::_fecho('I\'m alive'); /* ~namespace Logger; */ |
Látható, hogy az osztály végén ki van kommentelve egy sor, mely kommentje feloldásával arra hivatott, hogy ellenőrizzük vele, hogy a fájl valóban betöltődött-e a PATH-ra.
Ez az egyszerű megoldás számos továbbfejlesztési lehetőséget rejteget magában. Ilyenek például:
- Logok szintjének megkülönböztetése. (Pl. log 1. szint, log 2. szint, hiba 1. szint, stb.)
Konstansok bevezetésével, melyek ki/be kapcsolhatóak (bool típus, pl. localhost-on szükséges a debug, éles rendszeren nem, valamint más log-szintek jelenjenek meg egy teszt oldalon, mint az élesen.) - Egyedi string azonosító más objektum-példányoknál (részletesebb kimenet, minden oldalbetöltés egy-egy példányosítás.)
- Kerekített időbélyegek használata. (pl. minden 5 percről készüljön csak új fájl.)
A lista folytatódhatna. Ez a kis ízelítő talán felkeltette az érdeklődést, hogy milyen irányban lehetne elindulni, ha hibát kell/akarunk keresni. Ez egy remek eszköztár a hátizsákunkban, használjuk hát bátran.