Klaidų apdorojimas PHP aplinkoje

Šio straipsnio tikslas – papasakoti apie klaidų apdorojimą ir teikiamą naudą.

Dažnas nepatyrės programuotojas klaidų rodymą tiesiog išjungia arba naudoja operatorių @. Tokiu atveju, programavimo procese, nesimato daromos klaidos, pavyzdžiui naudojamas neapibrėžtas kintamasis, naudojamas masyvo elementas kurio nėra ir panašiai. Tokio tipo klaidos gali likti ir nepastebėtos, nes PHP kalboje tokiems atvejams yra taikomos tam tikros taisyklės, pavyzdžiui jei bandome gauti reikšmę iš kintamojo kurio nėra, gausite tuščią eilutę. Dažnas programuotojas to net nežino arba apie tai nesusimąsto. Tad programavimo procesui vykstant, tiesiog būtina įjungti klaidų rodymą.

Kas vyksta kai savo sukurtą programą atiduodate naudojimui? Yra labai pavojingas klaidų „tipas“, kai jos pasirodo esant tik tam tikroms specifinėms sąlygoms. Tai gali būti labai retai kviečiama sistemos funkcija arba nenumatytas funkcijos parametras kuris nepatikrinamas tinkamai. Tokias klaidas itin sunku pastebėti, tiek programavimo tiek ir testavimo stadijoje. Tokiu atveju standartinė veiksmų seka yra: naudotojas praneša apie problemą jūsų sistemos užsakovams, užsakovai praneša apie problemą jums, jei jums pasisekė ir buvo suteikta reikalinga informacija klaidai aptikti – ištaisote klaidą ir siunčiate pranešimą užsakovui, jei nepasisekė – tuomet susirašinėjate tol kol aptinkate klaidą. Jei tokioje grandinėje dalyvauja daugiau žmonių, tuomet sugaištama pernelyg daug laiko vienai klaidai aptikti ir išspręsti. Tokią situaciją reikia keisti. Tik kaip?

Sprendimo ieškoti ilgai nereikia. Pasirašome klaidų apdorojimą pagal savo poreikius, užsitikriname kokį nors būdą gauti surinktus duomenis ir tuomet apie klaidą sužinosite daug anksčiau, nei apie tai jums praneš užsakovai.

Taigi pateikiu savo reikmėms rašytą klasę, kuri rūpinsis klaidomis https://github.com/zygis/PHP-Error-Handler/blob/master/errorHandler.php. Klasei veikti būtinos sąlygos: Veikiantis ir neperpildytas kietasis diskas, PDO SQLite, Zend Framework, įjungtas „output buffering“ ir nustatyta tinkama laiko zona. Klasės kodą galima nesunkiai pakeisti, kad būtų pritaikytas kitiems karkasams nei Zend Framework arba naudoti standartines PHP funkcijas. Kaip minėjau ši klasė yra rašyta savoms reikmėms.

Zend Framework ErrorControler.php ar kitame panašią funkciją atliekančiame kontroleryje pridedame eilutes:

errorHandler::$showErrors = false;
errorHandler::exception(
    $errors->exception->getCode(),
    $errors->exception->getMessage(),
    $errors->exception->getFile(),
    $errors->exception->getLine(),
    $errors->exception->getTrace()
);
define('APPLICATION_END', '1');

Ir apie viską nuo pradžių. Klasės metode init atliekama inicializacija, sukuriami reikalingi objektai ir duomenų bazės, jei tokios prieš tai nebuvo. SQLite pasirinktas neatsitiktinai, mat visi reikalingi duomenys saugomi viename paprastame faile, kurį lengva perduoti atsakingiems asmenims, o jiems paprasta peržiūrėti turinį. Reikalui esant galima naudoti ir MySql duomenų bazę, tačiau prie reikalavimų tada prisidės ir veikiantis MySql serveris.

Taigi, nurodome PHP aplinkai, kad buo šiol klaidų apdorojimu pasirūpins mūsų klasė

register_shutdown_function(array("errorHandler", "fatal"));
set_error_handler(array("errorHandler", "error"));

Pirmoji funkcija iš esmės nėra skirta klaidų apdorojimui, ji nurodo ką iškviesti, kai PHP atliks savo darbą iki galo. Šiuo atveju reikia atsiminti, kad mes su funkcija set_error_handler nurodę savo metodą vistiek neapdorosime FATAL klaidų. Tokiu atveju naudinga turėti metodą kuris iškviečiamas programos darbo pabaigoje. Programos pabaigoje reikia nustatyti konstantą APPLICATION_END, kad žinotumėme ar darbas sėkmingai baigtas be klaidos, jei konstantos nėra – tai įvyko klaida ir ją registruojame. Labai svarbu atkreipti dėmesį į tai, kad pasinaudojus funkcija exit; PHP galutinai nutrauks darbą ir mūsų numatytų darbo pabaigos veiksmų nevykdys. Jei norite, kad tai neįvyktų naudokite die();

Duomenys apie klaidas rašomos į dvi skirtingas duomenų bazės lenteles. Pirmoje saugoma informacija apie klaidą, praktika parodė, kad tokių duomenų visiškai pakanka aptikti klaidai ir ją išspręsti. Antroje lentelėje agreguojama informacija apie klaidos pasirodymo laiką. Ši dalis svarbi, nes klaida gali kartotis daugybę kartų ir atitinkamai generuoti daug pasikartojančios informacijos, kuri tik apsunkintų duomenų perdavimą ir apdorojimą. Kokį laiko tarpą gali dengti viena eilutę pasirinkite patys pagal savo poreikius, tuomet reiktų arba pridėti minučių stulpelį lenteleje arba nuimti nereikalingus, tarkime agreguoti visos savaitės klaidas. Nemažiau svarbu pasirinkti kriterijus, pagal kuriuos atrinksite pasikartojančias klaidas. Tarkime tame pačiame faile ir toje pačioje eilutėje gali būti dvi skirtingos klaidos, su skirtingais pranešimais, tačiau gali būti ta pati klaida, kurios pranešimas priklauso nuo kažkokių veiksnių. Jei tai bibliotekos dalis, tuomet bibliotekos komponentą galima išsikviesti iš bet kurios programos vietos, tą aš laikyčiau kaip skirtingą klaidą ir stulpelyje trace rasiu man reikalingą informaciją. Tik čia išklyla kita problema, jei lentelėje ieškosiu klaidos su tokiu pat trace – didelė tikimybė, kad ta pati klaida prigeneruos nereikalingų įrašų, nes gali keistis ir dažniausia keičiasi perduodami parametrai. Tad nusprendžiau, kad aukso viduriukas bus paskaičiuoti elementų kiekį masyve. Klausimas lieka atviras, tai galite savo mintis pateikti komentaruose.

Dar vienas svarbus metodas yra showError, čia galima arba išvesti kažkokį draugišką ir/ar gražų pranešimą naudotojui, arba nukreipti kokiu nors adresu. Šiuo metu čia palikta vietos vaizduotei.

Ką daryti su surinktais duomenimis – vėl pasirinkimo reikalas. Tai gali būti siuntimas el. paštu, failo įkelimas į nurodytą ftp serverį, duomenų atvaizdavimas jūsų programos administracinėje dalyje arba koks pranešimas apie aptiktas klaidas ir siūlymas jas nusiųsti programuotojams. Bet kokiu atveju tai reikia pasirinkti pagal konkrečią situaciją.

Ateityje planuoju gaminti centalizuotą sistemą tokių klaidų surinkimui, kur būtų pateikiama agreguota informacija įvairiais pjūviais, kad būtų galima nustatyti problemines vietas, dažniausia kylančias problemas ar net problemas sukeliančius bendradarbius. Realiai pradejus naudoti klasę, gali būti, kad ji keisis, tą matysite GIT HUB repositorijoje.

Žygimantas

Lead developer at Soundest. Zend Certified Engineer.

More Posts - Website

Žymos: , , ,

4 komentarai

  1. xeranas

    „nustatyti problemas sukeliančius bendradarbius“

    I sense dark side in your heart! 😀

  2. Visai ne „dark side“, problemų sprendimų būdų yra daug. Svarbiausia problemas rasti, bei išsiaiškinti priežastis, tik taip gali būti užkertamas kelias pasekmėms.

    • Pritariu Žygimantui. Ir pridursiu šiek tiek nuo savęs. Jei nori, kad projektas klestėtų ir augtų reikia naudotis apsisaugojimo priemones, kad veliau nereikėtų vesti 😀

  3. ta klase gal ir nieko tik su zend gaila dar jo neisstudijaves

Parašykite komentarą

El. pašto adresas nebus skelbiamas. Būtini laukeliai pažymėti *

Galite naudoti šias HTML žymas ir atributus: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>