Utisci korisnika

"Želim da kazem da iako sam tek na pola, da sam oduševljena ovim načinom na koji stvari funkcionisu!" Stanislava Kraguljac, Beograd

Pre nepunih mesec dana kupila sam paket kurseva: PRIPREME ZA POLAGANJE CAMBRIDGE INTERNATIONAL DIPLOMA IN BUSINESS. Obično neki opšti utisak formiramo na kraju, ali ja u ovom trenutku želim sa…


Kompletna lista utisaka

Testiranje online

Arhitektura računara

Za one koji žele da znaju više.

Windows OS

Ovo bi svakako trebalo da probate.

Odnosi s javnošću

Koliko znate PR?

Pogledajte još neke od testova

Newsletter

Ukoliko želite da Vas redovno obaveštavamo o novostima sa Link eLearning sajta prijavite se na našu newsletter listu.

Ime:

Prezime:

Email:


Anketa

Arhiva anketa

BAZA ZNANJA


Kurs: - Core PHP Programming

Modul: Bezbednost i Debug

Autor: Vladimir Marić

Naziv jedinice: Rukovanje greškama


Materijali vezani uz ovu lekciju:

- Test rukovanje greškama
- Rukovanje greškama (PDF dokument)



Rukovanje greškama veoma je bitan element u svakom programskom jeziku, na praktično svim platformama. Nikada ne možemo biti potpuno sigurni, šta će i kada korisnik uraditi, kao ni kada će sistem i njegovi resursi, iz nekog razloga, omesti naš program u pravilnom izvršavanju.

Upravo iz tog razloga, obaveza programera je da predvidi koje tačke u programu predstavljaju potencijalnu opasnost po njegovo izvršavanje i da te pozicije obezbedi dodatnim zaštitnim sistemima.

Najbolnije tačke jedne aplikacije su trenutci kada se ta aplikacija obraća resursima. A ti resursi, odnosno, njihovo poreklo, najčešće je baza podataka ili fajl sistem. Pored njih, kritični trenutci događaju se i prilikom svakog korisničkog ulaza u aplikaciju (unos podataka), zatim striminga, kominikacije sa uređajima...

Osnovno rukovanje greškama je dosta jednostavno. Treba samo ispoštovati sledeći set pravila:

  • Staviti kritičan deo u poseban blok
  • Staviti alternativni deo u poseban blok

To možemo uraditi ručno ili putem try catch blokova, u zavisnosti od tipa greške koji očekujemo i toga da li je u stanju da bude obrađena kao izuzetak.


Ručna obrada grešaka na najnižem nivou

Pre nego što pristupimo nekom resursu, najbolje je ispitati da li taj resurs postoji i na osnovu toga nastaviti delovanje programa. Na primer:

<?php
$file=fopen("mojFajl.txt","r");
?>

Ukoliko se fajl mojiPodaci.txt ne nalazi u folderu aplikacije, ovaj kod će izazvati grešku. Zato bi prethodno trebalo proveriti da li fajl postoji i u odnosu na to, obezbediti ga:

<?php
if(!file_exists("mojFajl.txt"))
 {
  $file=fopen("mojFajl.txt","w");
//ovde bi trebalo proći kroz punjenje fajla podacima 
  fclose($file);
 }
$file=fopen("mojFajl.txt","r");
?>

Ili, jednostavno, prekinuti izvršavanje programa:

<?php
if(!file_exists("mojFajl.txt "))
 {
 die("Nepostojeci fajl");
 }
else
 {
 $file=fopen("mojFajl.txt ","r");
 }
?>


die()

Ova funkcija trenutno prekida izvršenje programa uz emitovanje (ili bez njega) korisnički definisane poruke. Ukoliko naime, dalje izvršenje programa zavisi od resursa koje treba da pročitamo (na primer od fajla mojFajl.txt u prethodnim primerima), onda svakako treba prekinuti dalje izvršavanje programa, ukoliko tog resursa nema.

U ovom primeru, ukoliko fajla nema, biće ispisana poruka greške, zatim poruka funkcije die (kraj) i izvršavanje će biti prekinuto.

<?php
$file=fopen("mojFajl.txt ","r") or die("kraj");
?>


Ručno emitovanje grešaka

U prethodnom primeru, prekidali smo izvršavanje programa funkcijom die(). Takođe, moguće je i emitovanje sopstvene poruke o grešci bez prekidanja izvršavanja. Ova linija koda će na poziciji na kojoj se nalazi, emitovati poruku o grešci.

trigger_error("Moja greška"); 

Tip na ovaj način emitovane greške će biti 1024 (Notice), što možda nije nivo ozbiljnosti koji želimo da predočimo korisniku. Da bismo ovo promenili, možemo eksplicitno, kao drugi parametar, uneti jedan od tri tipa grešaka koje ova funkcija prihvata i čije konvencije bi trebalo da poštujemo pri korišćenju:

  • E_USER_WARNING (512) – Greška koja utiče na rad aplikacije (npr, nismo pronašli resurse), ali aplikacija može da nastavi sa radom
  • E_USER_NOTICE (1024) – Samo obaveštenje; koristi se kada želimo korisnika da upozorimo na neku anomaliju u aplikaciji
  • E_USER_ERROR (256) – Ova greška treba da prethodi prekidu izvršavanja programa.


Na primer:

trigger_error("Moja greška", E_USER_WARNING); 


 
Ručno rukovanje greškama

Pored sopstvene aktivacije poruke o grešci, možemo napraviti i funkciju koja će presresti grešku i biti izvršena umesto ugrađene funkcije za rukovanje greškama, odnosno, sopstevni rukovalac greškama.

Ovakva funkcija prihvata parametre, broj greške, poruku greške, fajl koji je izazvao grešku, liniju greške, dump (niz varijabli i njihovih vrednosti aktivnih u trenutku greške). Ovi parametri su opcioni, ali njihov redosled treba poštovati pri izgradnji funkcije.

function mojHendler($brojGreske, $porukaGreske)
 {
  echo $brojGreske . “ “ . $porukaGreske;
 }

Nakon što napravimo funkciju koja želimo da rukuje greškama, potrebno je da je inicijalizujemo kao podrazumevani rukovalac greškama:

set_error_handler("mojHendler");

Nakon toga, sve greške, će biti, umesto u ugrađeni rukovalac, prosleđivane u našu ručno kreiranu funkciju.

Lista kodova (brojeva) greške, u odnosu na funkciju trigger_error, ovde je malo proširena i sastoji se od 7 kodova:

  • E_WARNING (2) - Greška koja ne prekida rad aplikacije ali utiče (nema resursa...)
  • E_NOTICE (8) – Samo obaveštenje
  • E_USER_ERROR (256) – Fatalna greška, prekida se izvršenje
  • E_USER_WARNING (512)
  • E_USER_NOTICE (1024)
  • E_RECOVERABLE_ERROR (4096) – Fatalna greška, koju je moguće obraditi u try catch bloku
  • E_ALL (8191) – Sve vrste grešaka

Greške iz ove liste, možemo priključiti čak i samom hendleru, kroz parametar funkcije set_error_handler:

set_error_handler("mojHendler", E_USER_NOTICE);

U ovom slučaju, kroz naš hendler, proći će samo greške tipa E_USER_NOTICE, dok će ostale greške biti obrađivane kroz ugrađeni hendler

Evo jednog primera kompletnog koda:

<?php
//kreacija funkcije-hendlera
function mojHendler($brojGreske,$porukaGreske)
 {
 echo $brojGreske . " " . $porukaGreske; 
 }
//prepisivanje sistemskog hendlera korisnickim
set_error_handler("mojHendler");
//izazivanje greske unosom neinicijalizovane varijable
echo($mojaVarijabla);
?>

Nakon uhvaćene greške, najbolje je proslediti je u neki log u bazi ili na fajl sistemu. Loger za neki specifičan sistem (na primer, da pamtimo logove u bazi) možemo napisati ručno, dok za standardne tipova log-a možemo koristiti i ugrađenu funkciju error_log().

Ova funkcija prima do četiri parametra: poruku greške, tip logovanja, destinaciju i zaglavlje.

Poruka greške je bilo koja korisnička poruka, za koju želimo da bude zapamćena u logu. Tip logovanja predstavlja, zapravo, destinaciju slanja ovog log-a, pri čemu je:

  • 0 – Default (koristi se sistemski definisan log),
  • 1 – Mail (log entry se šalje na mail),
  • 3 – Fajl (log entry se upisuje u fajl)
  • U slučaju da je tip destinacije 1 i 2 (mail ili fajl), potrebni su i dodatni parametri (zaglavlje i destinacija za mail i adresu destinacioni fajl za fajl).


<?php
error_log("Moja greska",1, "ciljniMail@mail.com","From: mojMail@mail.com");
?>

<?php
error_log("Moja greska",3, "c:/mojfajl.log");
?>


Rukovanje izuzecima

Nije uvek moguće rešavanje problema sa resursima (i sličnih) putem uslovnih izvršavanja koda. Ponekad je jednostavno, potrebno, pokušati nešto da bi se znalo da li to nešto može da se uradi. U tom slučaju, treba nam mehanizam koji će reagovati tek nakon dolaska do greške, a da pri tom ne poremeti normalan rad programa. Ovakav mehanizam postoji i naziva se rukovalac izuzecima.

Rukovalac izuzecima je pojam blisko vezan za objektno orjentisano programiranje, jer u stvari, izuzatak jeste nešto što je karakteristično za određeni događaj određene klase.
Vratimo se na primer sa početka lekcije, gde smo pokušali da pročitamo nepostojeći fajl:

<?php
$file=fopen("mojFajl.txt","r");
?>

... gde smo problem nepostojećeg fajla rešili tako što smo postavili uslov ispred čitanja:

if(file_exists("mojFajl.txt")) 

Recimo da je sve ovo sada deo jedne klase koja rukuje fajlovima.

<?php
 function citaj($fajl)
 {  
    if(file_exists($fajl))
    $file=fopen($fajl,"r");
 }
?>


Poziv funkcije citaj() ove klase, neće prikazati grešku, što je očekivano. Takođe, mogli smo i ubaciti logiku, koja bi izbacila poruku o nepostojanju fajla. Ali, da bi naša greška o nepostojećem fajlu, bila u konvenciji izuzetaka, odnosno, da bi korisnici klase (ukoliko je izuzetak izbačen iz klase) ili mi sami mogli da je „uhvate” kao standardan izuzetak, standardnim metodama za hvatanje izuzetaka, potrebno je da i objekat koji emitujemo prilikom obrade ove naše greške, bude tipa izuzetak.

<?php
function citaj($fajl)
 {  
    if(!file_exists($fajl))
 throw new Exception("Fajl ne postoji");
else
    $file=fopen($fajl,"r");
  }
//izazivanje izuzetka
citaj("mojFajl.txt");
?>


Ovako emitovanu grešku (izuzetak), lako hvatamo upotrebom try-catch bloka. Potrebno je samo da naznačimo u kom delu predviđamo događanje izuzetka (u ovom slučaju to je poziv metode citaj()) i stavimo ga u try blok, a zatim dodamo alternativni kod (koji treba da se izvrši ako try blok ne uspe) u catch blok. Catch blok prihvata parametar tipa Exception, koji sadrži propertije i metode za razotkrivanje određenih detalja vezanih za sam Exception.

try
{
citaj("mojFajl.txt");
}
catch(Exception $e)
{
echo $e;
}

Umesto new Exception, koji smo „izbacili” iz funkcije citaj(), mogli smo da izbacimo i instancu sopstvene klase izuzetaka. Naravno, ukoliko smo je prethodno napravili; a možemo je napraviti nasleđivanjem klase Exception i dodavanjem svojih elemenata:

class mojIzuzetak extends Exception
 {
 public function errorMessage()
  {
   return "moj izuzetak";
  }
 }
 

 

Vežba 1

Problem:

Data je sledeća promenljiva:

$whiteList = array("index.php","index1.php","index2.php");


Potrebno je napraviti funkciju includeFile, koja će prihvatati naziv fajla, proveriti da li taj naziv postoji u nizu i da li postoji fajl sa tim imenom. Ukoliko fajl ne postoji u nizu ili na fajl sistemu, potrebno je prekinuti funkciju emitovanjem izuzetka. U suprotnom, treba učitati fajl funkcijom include ili require.

Potrebno je izvršiti poziv funkcije u try catch bloku.


Rešenje:

<?php
    $whiteList = array("index.php","index1.php","index2.php");
    function includeFile($file)
        {
            global $whiteList;
            if(!in_array($file,$whiteList))
                throw new Exception("No file in whitelist");
            else if(!file_exists($file))
                throw new Exception("Filename is not valid");
            else
                include $file;
        }
    try
    {
        includeFile("index.php");
    }
    catch(Exception $ex)
    {
        echo $ex->getMessage();
    }
?>

 

Najvažnije iz lekcije:

  1. Najčešći uzrok grešaka jeste problem u pristupu spoljnim resursima (fajlovi, baza, korisnički ulaz, strim)
  2. Greške se predupređuju logikom u kodu, obradom izuzetaka, obradom grešaka
  3. Moguće je ručno aktivirati grešku
  4. Moguće je napraviti sopstveni hendler za rukovanje greškama, koji će hvatati sve greške ili one određenog tipa i tim hendlerom prepisati ugrađeni hendler.
  5. Moguće je izbaciti sopstveni izuzetak tokom izvršavanja koda
  6. Moguće je napraviti sopstvenu klasu izuzetaka koja nasleđuje klasu Exception
  7. Izuzecima se rukuje tako što se glavni kod stavlja u try blok a alternativni kod u catch blok, pri čemu, oba bloka moraju postojati i catch blok mora prihvatiti promenljivu koja je tipa izuzetak.

Smatrate da je ova lekcija korisna?  Preporučite je. Broj preporuka:3


Molimo Vas unesite svoje podatke i dobićete pristup besplatnim lekcijama.

Ime: 
Prezime: 
Email: