Un trigger reprezintă o “subrutină” stocată în baza de date care conţine cod executabil, al cărei execuţii se va declanşa automat la întâmplarea unui anume eveniment. Spre deosebire de procedurile stocate sau funcţiile definite de utilizator care sunt definite global într-o bază de date, trigger-ii sunt strict legaţi de tabele, ei se definesc în relaţie cu acestea iar acţiunile lor sunt menite să aibă sens asupra lor sau pornind de la fiecare în parte.

Există două tipuri de trigger-i, cei care afectează toate înregistrările dintr-o tabelă şi cei care afecteză doar o anume înregistrare. Ambele însă au efect(se declanşează) atunci când una din următoarele operaţii este lansată asupra tabelei: INSERT, UPDATE, DELETE, iar pentru aceste operaţii se vor defini trigger-i care au efect ÎNAINTE sau DUPĂ ce instrucţiunea a fost executată pe baza de date.


CREATE
[DEFINER = { user | CURRENT_USER }]
TRIGGER trigger_name trigger_time trigger_event
ON tbl_name FOR EACH ROW trigger_stmt

În MySQL trigger-ii au fost introduşi în versiunea 5.0.2 iar pentru crearea unuia este necesară deţinerea de drepturi corespunzătoare. Clauza DEFINER va stabili nivelul de drepturi necesare pentru a se putea executa trigger-ul;trigger_name reprezintă numele trigger-ului, iar trigger_time şi trigger_event definesc situaţia în care trigger-ului se va executa.

trigger_time reprezintă momentul în care se va executa trigger-ul relativ la operaţia ce s-a lansat pe acea tabela, şi poate avea următoarele valori: BEFORE şi AFTER. trigger_event reprezintă însuşi acţiunea la care se face referire, iar acest parametru va avea una din următoarele valori:

  • INSERT caz în care trigger-ul va fi lansat la execuţia unei instrucţiuni INSERT, LOAD DATA sau REPLACE pe baza de date;
  • UPDATE caz în care trigger-ul se va lansa la apelul unei instrucţiuni UPDATE
  • DELETE caz în care trigger-ul va fi lansat la ştergerea de înregistrări folosind instrucţiunea DELETE; trigger-ul nu va fi lansat la execuţia instrucţiunii TRUCATE sau DROP TABLE

tbl_name reprezintă numele tabelei la care trigger-ul va reacţiona iar trigger_stmt reprezintă instrucţiunea SQL ce va fi lansată; în caz că se doresc execuţia mai multor instrucţiuni acestea vor fi introduse intre cuvintele BEGIN şi END. Toate restricţiile discutate în cadrul articolului Subrutine în MySQL sunt valabile şi pentru trigger-i.


/*
trigger ce va fi lansat inaintea unei instructiuni INSERT
*/
CREATE TRIGGER trTestInsert BEFORE INSERT ON products
FOR EACH ROW BEGIN
SET NEW.products_guid = UUID();
INSERT INTO audit (user_id, products_guid, audit_action) VALUES (NEW.users_id, NEW.products_guid, 'insert');
UPDATE categories SET categories_count = categories_count + 1 WHERE categories_id = NEW.categories_id;
END;
/*
trigger ce va fi lansat dupa o instructiune DELETE
*/
CREATE TRIGGER trTestDelete AFTER DELETE ON products
FOR EACH ROW BEGIN
SET NEW.products_guid = UUID();
INSERT INTO audit (products_guid, audit_action) VALUES (OLD.products_guid, 'delete');
UPDATE categories SET categories_count = categories_count - 1 WHERE categories_id = OLD.categories_id;
END;

În definirea celor 2 trigger-e am folosit două cuvinte rezervate MySQL, şi anume: OLD şi NEW. Prin aceste două referinţe vă puteţi adresa la câmpurile din înregistrările care au fost sau urmează a fi procesate. Astfel la o inserare în baza de date NEW va conţine toate câmpurile din înregistrarea pentru care a fost declanşat acel trigger, pe când la un trigger pe o instrucţiune UPDATE, în OLD veţi găsi toate informaţiile legate de înregistrarea ce a fost modificată.

Trigger-ii ajută la creşterea gradului de automatizare a unor procese, pot fi folosiţi foarte bine la logarea de date sau informaţii, ori folosit la crearea datelor de audit. Nu în ultimul rând pot fi folosiţi şi la aplicarea unor restricţii suplimentare asupra operaţiunilor făcute asupra bazelor de date.

Vorbeam într-un articol precedent cum că suportul pentru obiecte a fost regândit şi rescris odată cu versiunea 5 a limbajului de programare PHP, pentru a oferi mai multă flexibilitate programatorilor prin facilităţi noi dar şi prin performanţă sporită.

Două dintre facilităţile nou oferite sunt clasele abstracte şi interfeţele. Acestea derivă din teoria programării orientate pe obiect şi sunt nişte unelte puternice pentru crearea de module integrabile sau de diverse interfeţe ale aplicaţiilor şi sunt foarte utile în cazul proiectelor dezvoltate în echipe numeroase de programatori.

Abstractizarea

Abstractizarea este procesul de simplificare a realităţii complexe prin modelarea de clase cât mai generale şi cât mai apropiate de problema care se tratează. De exemplu, în realitatea de zi cu zi o clasă generală numită maşină are un algoritm general de funcţionare, deşi un BMW s-ar putea sa meargă mai bine decât un Renault deşi ambele au în componenţa lor un motor, 4 roti şi un volan, asemenea unei Dacii.

Revenind la problema programării orientate pe obiect, o clasă abstractă este o clasă care nu se poate instanţia, deci care nu poate avea direct obiecte de sine stătătoare. Aceasta poate fi doar moştenită deci are sens în limbajele de programare care suportă această facilitate. Ca şi în realitate, folosirea acestor clase se face când se doreşte crearea de concepte abstracte, care apoi vor fi extinse prin adăugarea de funcţionalităţi noi şi particularizate pentru fiecare moştenire. Aceste clase vor fi definite în aşa fel încât clasele moştenitoare vor trebui sa implementeze acele metode, creând astfel clase generice, care vor avea de cele mai mult ori metode goale sau parţial implementate. Clasele care vor moşteni aceste clase abstracte sunt clase concrete, şi vor trebui să aibă o funcţionalitate concretă, bazată pe scheletul abstract din clasa părinte.

PHP 5 introduce aşadar, conceptul de abstractizare a claselor şi a metodelor. Astfel, orice clasă care conţine o metodă abstractă va trebui declarată ca fiind abstractă. Aceste metode declarate abstracte sunt doar declarate, nu şi implementate, deci nu vor conţine în corpul lor cod sursă. În cadrul claselor moştenite, toate acele metode declarate abstracte vor trebui redeclarate şi implementate, însă cu o vizibilitatea cel puţin egală cu cea declarată în clasa abstractă. Clasele abstracte pot conţine şi metode neabstracte, care pot fi şi definite în cadrul clasei abstracte şi care vor fi moştenite ca atare în clasele copil.

Vom exemplifica acest concept cu o situaţie întâlnită în practică. Vom considera un magazin virtual care acceptă la plată mai multe modalităţi de plată cum ar fi: plata la livrare, plata cu cardul, plata prin ordin de plata, plata prin rate bancare, plata prin PayPal etc. Se poate observa în situaţia curentă că problema a cărei soluţii încercăm s-o găsim este cea a plăţii, deci putem abstractiza o clasă generică numită plată. Această clasă va defini structura unei astfel de modalităţi de plată şi totodată fluxul care îl va urma orice proces de plată. Moştenitorii acestei clase abstracte vor trebui să implementeze aceste metode generale în stilul specific modalităţii de plată care o reprezintă. Sa considerâm următoarele scenarii:

  • în cazul în care se alege plata la livrare nu se va efectua nici o operaţiunie specială
  • în cazul plăţii folosind un card bancar, clientul va fi redirecţionat către un procesator de plăţi online care îi va procesa cererea de plată şi va reîntoarce clientul la magazin alături de răspunsul de confirmare sau eroare a tranzacţiei
  • în cazul plăţii prin ordin de plată se va mai completa o lista de plaţi prin OP pentru a fi verificate ulterior
  • în cazul plăţii prin rate bancare comanda respectivă va fi pusă într-un status special, de aşteptare, pentru a primi documentaţia necesară aprobării creditului de la client
abstract class payment
{
    protected $info, $customer_id, $amount;
    
    public function __construct($customerID, $amount)
    {
        
    }
    
    abstract public function doBeforeProcess() ;
    
    abstract public function process();
    
    abstract public function doAfterProcess();
    
    public function getInfo()
    {
        return $this->info;
    }
}

Aşadar am definit această clasă abstractă care defineşte modul de funcţionare a unei modalităţi de plată. Plata propiu-zisă va fi efectuată în cadrul metodei process(); metodele doBeforeProcess() şi doAfterProcess() vor fi folosite pentru acontrola diverse acţiuni ce trebuiesc efectuate înainte respectiv după efectuarea plăţii. Iată şi implementările claselor moştenitoare:

class pay_at_delivery extends payment 
{
    public function __construct($customerID, $amount)
    {
        $this->info = "Aceasta metoda presupune achitarea produsului cash la primirea acestuia.";
        $this->customer_id = $customerID;
        $this->amount = $amount;
    }
    
    public function doBeforeProcess()
    {
        return true;
    }
    
    public function process()
    {
        return true;
    }
    
    public function doAfterProcess()
    {
        return true;
    }
}

Modalitatea de plată la livrare nu presupune nimic special, decât inserarea în baza de date a comenzii clientului care vom presupune ca se realizează unitar în mediul în care se apelează modalitatea de plată. Metodele abstracte vor trebui implementate, ca regula a abstractizării, însă ele nu vor realiza nimic concret.

class credit_card extends payment 
{
    const PROCESSOR_SERVER = 'https://secure.credit-card-processor.com/cgi-bin/';
    const MERCHANT_ID = '1234567890';
    protected $post_params;
    
    public function __construct($customerID, $amount)
    {
        $this->info = "Veti fi redirectionati catre un procesator de carduri bancare pentru a finaliza plata.";
        $this->customer_id = $customerID;
        $this->amount = $amount;
    }
    
    public function doBeforeProcess()
    {
        $this->post_params = 'CUSTOMER=' . $this->customer_id . 
                             '&AMOUNT=' . $this->amount .
                             '&MERCHANT_ID=' . self::MERCHANT_ID ;
    }
    
    public function process()
    {
        $this->doPostToGateway($this->post_params);
    }
    
    public function doAfterProcess()
    {
        if ($transactionOK)
    	{
            $this->insertIntoSpecialDb($response);
    	}
    }
}

Şi în cazul plăţii prin card bancar am implementat toate metodele abstracte, însă aici am adăugat şi ceva funcţionalitate acestora. Majoritatea procesatorilor de carduri bancare pun la dispoziţie un gateway (interfaţă de comunicare) prin care se face transferul de informaţii de la comerciant la procesator şi invers. Acesta gateway va trebui accesat cu un set de parametrii pentru a identifica intenţia de tranzacţie şi la rândul lui, va returna un răspuns pentru a confirma(sau infirma) validitatea cardului şi a tranzacţiei efectuate de către client. Metoda de preprocesare va pregăti parametrii de identificare a tranzacţiei, care vor fi accesaţi din metoda de procesare. Metoda de trimitere a parametrilor se poate face prin cURL sau prin redirecţionare, şi am presupus-o funcţională în metoda doPostToGateway(). În final, în cazul în care tranzacţia este reuşită vom insera o înregistrare într-o tabelă separată din baza de date, cu ajutorul metodei insertIntoSpecialDb().

Cazul plăţii prin ordin de plată se va adăuga în postprocesare o înregistrare în tabela destinată acestor documente. În cazul plăţii prin rate, se va stabili o stare specială a comenzii de aşteptare a aprobării creditului. Metoda getInfo() declarată şi definită în cadrul clasei abstracte, va fi moştenită de către toate clasele copil şi va fi accesobilă în orice instanţiere a acestora. Este o metodă care va returna continutul variabilei protejate info care diferă de la o clasă la alta, li setată în cadrul constructorului.

Este evident că, deşi reală, situaţia dezvoltată de noi este una minimală. În cadrul unei procesări de carduri reală procesatorul va dori trimitearea mai multor parametrii, precum şi a unor chei criptate, pentru a evita frauda pe cât de mult posibil. La fel şi în cazul plăţii prin rate, procesarea poate fi constituită dintr-un formular care ar fi completat de către client cu datele lui financiare, iar postprocesarea ar putea însemna trimiterea pe email a formularelor completate şi a acordurilor de credit pentru a fi semnate de către acesta.

Interfeţe

O interfaţă nu este o clasă. O interfaţă nu este o clasă. Repetarea nu este o greşeală de tipar. O interfaţă este pur şi simplu o entitate care se defineşte folosind cuvântul cheie interface. O interfaţă nu are o implementare, este doar o semnătură, sau altfel spus are doar definiţia unor metode fără implementarea lor. Ca o asemănare cu abstractizarea, interfatarea crează doar scheletul unei clase ce urmează a fi implementate.

O interfaţă este aşadar un schelet care defineşte un set de metode ce urmează a fi suprascrise şi implementate în clasele copil. Clasa abstractă poate avea şi o funcţionalitate de bază care va fi moştenită în toate implementările ei.

interface iTemplate
{
    public function setVariable($name, $var);
    public function getHtml($template);
}
/*
implementarea interfetei
*/
class Template implements iTemplate
{
    private $vars = array();
  
    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }
  
    public function getHtml($template)
    {
        foreach($this->vars as $name => $value) {
            $template = str_replace('{' . $name . '}', $value, $template);
        }
        return $template;
    }
}

O clasa poate implementa mai multe interfețe, dar nu poate moșteni mai multe clase abstracte. Implementarea multiplă se face doar dacă nu există conflicte de nume între clasele părinte.

Un script PHP este în esență o înşiruire de instrucţiuni. Instrucţiunile pot fi de mai multe feluri: atribuiri, apeluri de funcţii, structuri de control sau chiar instrucţiunea vidă. Aceste instrucţiuni sunt delimitate la finalul lor de către semnul punct şi virgulă. Totodată ele pot fi grupate într-o singură instrucţiune compusă, care la rândul ei devine o instrucţiune de sine stătătoare, înglobând mai multe instrucţiuni simple între două acolade.

Decizia

În crearea unui script, sau în general a oricărui program, vă veți întâlni cam în 100% din cazuri cu luatul de decizii. Sau mai bine zis cu scris cod care să ia decizii pe loc în momentul rulării aplicaţiei respective. Deşi rudimentară, este una din tehnicile de bază în programare (alături de iteraţie), fără de care probabil programarea dacă ar fi existat ar fi fost o meserie destul de greoaie. Se bazează pe faptul că în timpul execuţiei se poate dori execuţia unor anume instrucţinui în detrimentul altora în funcţie de, să zicem, nişte parametrii proveniţi de la utilizatori, deci de a lua o decizie: ce instrucţiune, sau set de instrucţiuni, să execut? Există două structuri de control care vă pot ajuta în luarea acestor decizii: if şi switch.

Instrucțiunea IF-ELSE-ELSEIF este o instrucţiune întâlnită în majoritatea limbajelor de programare şi mai este întâlnită sub denumirea de instrucţiunea decizională simplă. Astfel aceasta dă posibilitatea de a alege dintre două sau mai multe posibilităţi de execuţie a codului, folosind-se de niște condiţii testate în prealabil. Formatul general al acesteia este:


if ()

[elseif ()

elseif ()

else
]

Efectul acestei instrucţiuni este următorul: se evaluează condiţia din cadrul ramurei if, dacă aceasta are valoare logică de TRUE, atunci se execută instrucţiunea imediat următoare. În caz contrar se trece la prima ramură elseif(dacă există) testându-se condiţia şi executându-se instrucţiunea corespunzătoare în caz ca aceasta se evaluează la TRUE. Procesul continuă pentru toate ramurile elseif până când sunt terminate sau până la prima condiţie evaluată la TRUE. În caz ca nici una nu va fi găsită TRUE, se va executa instrucţiunea de pe ramura else, dacă există. De remarcat este faptul că se pot defini oricât de multe ramuri elseif şi doar una if sau else, şi că evaluarea la TRUE a unei condiţii face ca execuția să iasă din această structură de control. Totodată trebuie menţionat că oricare din ramurile definite suportă în corpul lor o singură instrucţiune; în cazul în care se dorește execuţia mai multor instrucțiuni acestea se pot grupa într-o instrucțiune compusă. Iată nişte exemple, pur didactice:


$number = 27;
if ($number % 2 == 0)
echo "Numarul este par";
else
echo "Numarul este impar";
/*
structura care foloseste si elseif
*/
if ($number % 3 == 0)
echo "Numarul este divizibil cu 3";
elseif ($number % 3 == 1)
echo "Numarul nu este divizibil cu 3, restul impartirii este 1";
else
echo "Numarul nu este divizibil cu 3, restul impartirii este 2";

În cazul în care o instrucțiune IF ar conține multe ramuri elseif, scrierea lor ar putea deveni greoaie, precum citirea şi înțelegerea lor. De aceea PHP dispune şi de o instrucțiune decizională multiplă: SWITCH. Switch are avantajul că permite testarea unei variabile, sau a unei aceleiași expresii cu mai multe valori şi să execute o serie de instrucțiuni în caz că acesta ar fi egal cu una din valorile conținute în ramurile case.


switch ()
{
case var1:
instructiune1;
[break;]
[case var2:
instructiune2;
[break;]
case varn:
instructiunen;
[break;]]
[default:
instructiune;]
}

Iată şi un exemplu concret:


$number = 27;
switch ($number % 3)
{
case 0:
echo "Numarul este divizibil cu 3";
break;
case 1:
echo "Numarul nu este divizibil cu 3, restul impartirii este 1";
break;
case 2:
echo "Numarul nu este divizibil cu 3, restul impartirii este 2";
break;
}

Spre deosebire de lanțul de if-uri care se pot forma, instrucțiunea switch este mult mai robustă, atât prin modul de scriere dar şi prin modul de lucru. Diferă de instrucțiunea if prin faptul ca expresia este evaluată o singură dată la început şi apoi este verificată cu toate valorile întâlnite în ramurile case până când acestea corespund. Poate exista și o ramură default, care va fi executată când nici una din valorile din case nu corespund cu valoarea evaluată. Instrucțiunea break este folosită pentru a evita executarea mai multor ramuri în cazul în care o valoarea expresiei evaluate este întâlnită în una din ramurile case. Considerăm următorul exemplu:


switch ($number % 3)
{
case 0:
echo "Numarul este divizibil cu 3";
case 1:
echo "Numarul nu este divizibil cu 3, restul impartirii este 1";
case 2:
echo "Numarul nu este divizibil cu 3, restul impartirii este 2";
}

Deşi cu valoarea nulă în practică, exemplul de mai sus dacă v-a primi un număr divizibil cu zero si va afişa mesajele (sau executa intrucţiunile) de pe toate ramurile existente sub prima ramură până când va întâlni o instrucţiune break, sau, cum e şi cazul nostru, până la finalul structurii. Totuşi, un exemplu carea ar avea ceva logică şi care ar scoate în evidenţă lipsa folosirii de break, ar fi următorul:


switch ($number % 3)
{
case 0:
echo "Numarul este divizibil cu 3";
break;
case 1:
case 2:
echo "Numarul nu este divizibil cu 3";
}

În caz că expresia se va evalua la valoarea 1 scriptul va executa instrucţiunile din ramura cu valoarea 1 (in cazul nostru nici unul) şi instrucţiunile din ramura cu valoarea 2. Procesul ar fi continuat dacă ar fi existat şi alte ramuri.

Iteraţia

Iterația este procedura de repetare a unui set de aceleaşi instrucţiuni în anumite condiţii. Astfel aceste structuri de control pot fi folosite de regulă pentru a aplica acelaşi tratament asupra unui set de date, sau chiar pe o singură informaţie, până când se obţine un rezultat dorit. Cele mai uzuale instrucţiuni iterative sunt while, do-while, for, foreach.


while ()
;

do
{
;
} while ();

Ambele structuri au rolul de a executa instrucţiunile din corpul lor până când expresiile respective ajung la valoarea TRUE. Diferenţa esenţială dintre ele este ca in cazul structurii while expresia este evaluată înainte ca orice iteraţie să aibă loc, deci corpul structurii while poate să nu fie executat niciodată, pe când în cazul instrucţiunii do-while expresia este evaluată după prima iteraţie, deci numărul minim de cicluri efectuate este de unu. Asemeni instrucţiunii decizionale simple, şi instrucţiunile iterative suportă în corpul lor doar execuţia unei singuri instrucţiuni, executarea mai mult instrucţiuni se face prin gruparea lor în una compusă.


/*
codul va afisa toate numerele de la 0 la 9
valoarea cu care $i va iesi din ciclu este 10
*/
$i = 0;
do {
echo $i;
$i++;
} while ($i < 10);
/*
codul următor are același efect cu cel de mai sus
*/
$i = 0;
while ($i < 10)
{
echo $i;
$i++;
}

În ambele cazuri, în instrucţiunile ce alcătuiesc corpul structurii, trebuie avută în vedere modificarea variabilei, sau a expresiei, care face scopul acelei expresiei, astfel se poate genera o bulcă infinită, buclă care nu se va termina într-un număr finit de paşi, ducând la o execuţie infinită a scriptului. In cazul celor doua exemple de mai sus, presupunem ca din corpul structurilor am scoate instrucţiunile de incrementare ale lui $i; acest lucru ar face ca valoarea lui $i să rămână tot timpul 0, deci mai mică decât 10, deci condiţia valabilă în orice iteraţie. Astfel de cazuri trebuiesc evitate.

Instrucţiunile for si foreach sunt tot instrucţiuni repetitive şi sunt considerate cele mai complexe structuri iterative din cadrul limbajului PHP.


for (expr-initiere; expr-testare; expr-iterare)
instructiune;

Modul de funcţionare al acestei structuri este următorul: la prima intrarea în structura se va executa necondiţionat expresia expr-initiere, care de regulă va conţine instrucţiuni de iniţializare de variabile ce vor fi folosite în interiorul for-ului. În continuare, la fiecare iteraţie se va evalua expr-testare, al cărui rezultat va decide dacă instrucţiunea din corpul for-ului va fi executată sau nu. În caz că expresia va fi evaluată la valoarea FALSE, instrucţiunea nu va fi evaluată iar execuţia programului va ieşi din această structură. În cazul evaluării la TRUE, corpul structurii va fi executat, iar la finalul acestuia se va executa şi expr-iterare. Ca şi în cazurile precedente, executarea mai multor instrucţiuni presupune gruparea lor într-una compusă şi aceeaşi atenţie trebuie acordată evitării de bucle infinite. Complexitatea aceste structuri constă în faptul că oricare din cele 3 expresii pot lipsi, dându-se astfel o mai mare libertate programatorului în controlul acestei structuri.

Structura foreach este o structură introdusă din versiunea 4 a PHP şi este creată special pentru a itera prin elementele unui vector şi poate fi folosită în 2 moduri:


foreach ($array as $valoare)

foreach ($array as $index => $valoare)

Prima variantă de utilizarea va extrage fiecare element al vectorului la fiecare iteraţie în interiorul variabilei $valoare, pe când ce-l de-al doilea exemplu va separa indexul de valoarea elementului în cele 2 valori. Micul neajuns al acestei structuri este acela că iteraţia se face pe o copie a vectorului, deci orice modificare asupra $index sau $valoare nu va avea efect în vectorul care se iterează.

Întreruperea şi continuarea

Break şi continue sunt două instrucţiuni cu care se pot controla toate structurile iterative în sensul opririi sau continuării execuţiei de la începutul buclei. Astfel, o instrucţiune break va determina ieşirea dintr-o structură repetitivă a execuţiei, pe când continue va determina întoarcerea la începutul buclei, evaluarea expresiei de testare (dacă este cazul) şi reluarea execuţiei.


for ($i = 0; $i < 10; $i++)
{
if ($i == 5)
continue;

echo $i . ',';

if ($i == 7 )
break;
}

Exemplul precedent va afişa numerele 0, 1, 2, 3, 4, 6, 7. În interiorul structurii for la atingerea valorii 5 a lui $i se va executa instrucţiunea continue care va muta execuţia la incrementarea lui $i, şi apoi la execuţia următorului ciclu. La întâlnirea lui 7, deşi va fi afişat, execuţia va paraşi structura for, datorită instrucţiunii break. Un exemplu mult mai practic de folosirea a lui break este acela în care se dispune de un set de date (numere de exemplu), şi se doreşte aflarea dacă un număr oarecare se află în acel set de date. Metoda cea mai simplă şi rudimentară este căutarea secvenţială, în care fiecare element al setului de date este comparat cu acea valoare, până când cele 2 valori conicid sau până setul de date este temrinat. Îmbunătăţirea considerabilă ar fi ca în momentul în care elementul a fost găsit, scriptul ca nu caute în elementele rămase ci să printeze un mesaj şi să încheie execuţia.


$array = array(1,4,2,8,6,3,9,0);
$searchNo = 8;
foreach ($array as $element)
{
if ($searchNo == $element)
{
echo "Numarul cautat a fost gasit";
break;
}
}

De notat este că în cazul instrucţiunilor imbricate repetitive, apelul lui continue sau break va determina continuarea sau întreruperea primului ciclu repetitiv în care instucţiunea a fost apelată. Dacă de exemplu se doreşte iesirea şi din cel de-al doilea, sau al treilea ciclu imbricat, se poate folosi următoarea sintaxă:


break 2;

Aşadar, este recomandat ca după fiecare apel a lui break să nu uitaţi terminarea instrucţiunii cu un punct şi virgulă, în caz contrar, dacă după aceasta există o instrucţiune care să returneze sau să se evalueze la o valoarea numerică, această valoare va fi pasată instrucţiunii break, lucru care poate afecta logica scriptului.

Subrutinele sunt mici bucăţi de cod executabil care sunt stocate într-o bază de date relaţională, definite de către utilizator ce are posibilitatea de a le chema atunci când situaţia o cere. La fel ca o funcţie definită de utilizator în cadrul unui limbaj de programare, o subrutină extinde funcţionalitatea nativă oferită de SGBD-ul în care se scrie această subrutină însă personalizată pe baza de date în care este scrisă şi structura acesteia.

Utilizatorii MySQL s-au putut bucura de aceste facilităţi începând cu versiunea 5 a bazei de date, moment în care acestea s-au introdus alături de view-uri sau trigger-i. Până în acest moment (2005), dezvoltatorii MySQL erau nevoiţi să stocheze aceste coduri în aplicaţie sau în diverse fişiere pe server. De-a lungul timpului s-au detaşat 2 şcoli de gândire dintre care unii susţin că funcţionalitatea legată de baza de date ar trebui sa stea în aplicaţie şi alţii care susţin că această funcţionalitate ar trebui sa stea în interiorul bazei de date. Evident, adevărul este undeva la mijloc. Majoritatea programatorilor nu se bazează exclusiv pe una din cele două modalităţi de gândire, de multe ori folosirea unei modalităţi este preferată pentru că aceasta face sens în diverse situaţii. Este interesant totuşi de observat că mulţi gânditori ai şcolii numite în aplicaţie au luat această poziţie pentru că nu exista altă varianta, neexistând proceduri stocate in trecut, şi că aceştia sunt din ce în ce mai puţini. Şi totuşi, de ce ar stoca cineva subrutinele într-o bază de date şi nu în aplicţie?

Avantajele principale ale subrutinelor stocate sunt acelea referitoare la portabilitate şi îmbunătăţire a funcţionalităţii. O subrutină definită în baza de date, va rula în orice condiţii şi pe orice platformă suportată de catre baza de date gazdă. Mai mult, fiind inglobate în baza de date nu are importanţă ce aplicaţie(limbaj de programare) se foloseşte din exteriorul acesteia pentru a le utiliza şi pentru a returna date. Acestea au şi mai multă logică când se folosesc mai multe tehnologii pentru a crea aplicaţii complexe şi interconectabile cu o bază de date centrală. Deasemeni acestea pot reduce considerabil traficul dintre aplicaţie şi baza de date, deci într-un final rezultând un timp de execuţie mai bun al acţiunilor dorite. Imaginaţi-vă o situaţie în care pentru a obtine o raportare este nevoie de interogarea bazei de date, de obţinere a unui set mare de date, prelucrarea acestora în cadrul aplicaţiei, iar apoi pentru fiecare element din setul de date se impune interogarea bazei de date pentru a obţine alt set de date. Este uşor de observat ca transmiterea datelor între baza de date şi aplicaţie este mult mai uşoară si mai puţin costisitoare daca s-ar face când toate datele ar fi pregătite: datele iniţiale ar rămâne în interiorul bazei de date şi nu s-ar trimite la aplicaţie, s-ar prelucra în baza de date, s-ar interoga din nou baza de date direct din interiorul subrutinei, iar la final după ce s-ar fi obţinut şi al doilea set de date, acestea (împreună cu primul) s-ar returna aplicaţiei.

Subrutinele sunt de două feluri: proceduri stocate şi funcţii definite de utilizator. Diferenţa dintre cele 2 este că cea din urmă poate returna o valoare scalară în timp ce procedura stocată poate “returna” şi unul sau mai multe seturi de date. Un exemplu simplu de procedură stocată este următorul:


CREATE PROCEDURE `inphpwetrust`.`spTest`()
BEGIN
SELECT * FROM tbl;
END;
/*
am definit o procedura stocata pe baza inphpwetrust numita spTest
care va returna datele din tabela numita tbl
*/
CREATE PROCEDURE `inphpwetrust`.`spTest`(in varID int)
BEGIN
SELECT * FROM tbl where tbl_id = varID;
END$$
/*
aceasta a doua procedura are rolul de a filtra datele din tabelul tbl dupa un parametru
*/

În definirea unei proceduri stocate se pot folosi mai mulţi parametri de intrare, care la rândul lor pot fi de mai multe feluri dintre care cel implicit este primul:

  • IN va transmite procedurii stocate un parametru care va putea fi folosit, modificat, însă modificările asupra lui nu vor avea efect în exteriorul procedurii
  • OUT nu va transmite procedurii stocate nici o valoare, sau o va considera pe cea trimisă ca fiind NULL; aceasta va fi modificată în interiorul procedurii iar modificările vor avea efect în exteriorul funcţiei
  • INOUT înglobează caracteristicile precedentelor; astfel se va putea trimite un parametru la procedura stocată care va putea fi folosit, modificat şi moridificările vor fi vizibile în exteriorul procedurii


/*
exemplu de procedura stocata ce se foloseste de parametri IN
acestia pot fi specificati sau nu
*/
CREATE PROCEDURE `spParamIN`(IN param1 varchar(10), param2 varchar(10))
BEGIN
select concat(param1, param2) as `concat`;
END;
/*
exemplu de procedura stocata ce se foloseste de parametri OUT
*/
CREATE PROCEDURE `spParamOUT`(IN param1 varchar(10), OUT param2 int)
BEGIN
set param2 = length(param1);
END;
/*
exemplu de procedura stocata ce se foloseste de parametri INOUT
*/
CREATE PROCEDURE `spParamINOUT`(INOUT param1 varchar(10), IN param2 int)
BEGIN
set param1 = param1 + param2;
END;

Folosire

În crerea unei proceduri stocate vă puteţi folosi de orice instrucţiune SQL existentă sau combinaţii ale acestor instrucţiuni. Se pot selecta data din bază, se pot adauga, edita sau şterge înregistrări ale diverselor tabele. Pe lângă aceste operaţii se pot folosi şi varibilele definite de utilizator. Acestea se declară local, folosind sintaxa:


DECLARE var1[,var2, ... , varn] TYPE [DEFAULT value]

Aceste variabile pot fi folosite fie pentru “bucătăria internă” a subrutinei, fie pentru a transmite anumite valori returnate din cadrul unor interogări SQL. Astfel, în exemplul urmator, prima instrucţiune SELECT va genera returnarea unui set de date, pe când cel de-al doilea va atribui valoarea din campul găsit către variabila indicată folosind operatorul INTO


CREATE PROCEDURE `spInto`(IN valID INT)
BEGIN
DECLARE tmpName VARCHAR(100);
SELECT * FROM customers;
SELECT name INTO tmpName FROM customers WHERE id = valID;
END;

Orice modificări aduse conţinutului varibilelor se poate face cu ajutorul operatorului SET, pe una sau mai multe variabile simultan. Se pot utiliza oricare din structurile de control existente in MySQL precum şi cursori sau tranzacţii.

Alte opţiuni

În definirea unei subrutine pot interveni şi alţi parametri ce pot influenţa modul de funcţionare a acestia. Modul general de definire a acestor subrutine este urmatorul:


CREATE
[DEFINER = { utilizator | CURRENT_USER }]
PROCEDURE nume_procedura ([parametrii[,...]])
[caracteristici ...] corp_rutina

CREATE
[DEFINER = { utilizator | CURRENT_USER }]
FUNCTION nume_functie ([parametrii[,...]])
RETURNS tip
[caracteristici ...] corp_rutina

parametrii:
[ IN | OUT | INOUT ] param tip

tip:
Orice tip valid de date MySQL

caracteristici:
LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'

corp_rutina:
Instructiuni valide SQL

LANGUAGE SQL este o opţiune care indica limbajul folosit pentru a crea subrutina. Acesta este limbajul implicit, deci poate fi ignorat. O procedură este considerata determinista (specificată prin opţiunea DETERMINISTIC) dacă aceasta va întoarce acelaşi set de date pentru aceeaşi parametri de intrare sau nedeterministă în caz contrar(implicit). Următoarele variabile au in MySQL doar rol informativ şi se referă la natura datelor folosite in cadrul rutinei, MySQL nerestricţionând intrucţiunile folosite în interiorul rutinei bazându-se pe aceste informaţii:

  • CONTAINS SQL specifică faptul că subrutina conţine cod SQL
  • NO SQL indică faptul că subrutina nu conţine cod SQL
  • READS SQL DATA indică faptul că subrutina citeşte date din baza de date (folosind instrucţiunea SELECT)
  • MODIFIES SQL DATA indică faptul ca subrutina va scrie(modifica) date din baza de date (folosind INSERT, UPDATE sau DELETE)

SQL SECURITY se referă la faptul că o subrutină va putea fi executată folosind drepturile utilizatorului care a creat (DEFINER) sau care invocă (INVOKER) acea subrutină. COMMENT permite adăugarea de informaţii suplimentare asupra acelei subrutine

Restricţii

Există câteva restricţii care MySQL le aplică în momentul creării de funcţii sau proceduri stocate şi de care este bine să se ţină cont.

  • instrucţiunile CHECK TABLE, OPTIMIZE TABLE, LOCK TABLES, UNLOCK TABLES, ALTER VIEW, LOAD DATA, LOAD TABLE nu pot fi folosite
  • folosirea de expresii predefinite cu ajutorul PREPARE, EXECUTE, DEALLOCATE PREPARE este interzisă; începând cu versiunea 5.0.13 această restricţie a fost ridicată în cazul procedurilor stocate, însă se menţine în cazul funcţiilor
  • folosirea instrucţiunii INSERT DELAY este identică cu INSERT în interiorul subrutinelor

Următoarele restricţii sunt aplicate doar funcţiilor definite de utilizator:

  • operaţiile care execută COMMIT sau ROLLBACK
  • operaţiile care returnează seturi de date
  • operaţia FLUSH
  • folosirea lor recursiv
  • modificări asupra tabelei are se operează citiri sau scrieri de către instrucţiunea care a chemat funcţia respectivă

Securitate

Pentru a avea posibilitatea de a crea proceduri stocate resepctiv funcţii, utilizatorul de MySQL trebuie să deţină drepturi de CREATE ROUTINE. MySQL va atribui automat drepturi pentru operaţiile ALTER ROUTINE şi EXECUTE pentru utilizatorul care a creat subrutina respectivă.

PHP 5 aduce un nou model al programării orientate pe obiect cu o multitudine de îmbunatăţiri şi facilităţi, spre bucuria programatorilor deja obişnuiţi cu pseudo-modelul din PHP 4. O facilitate care poate ajuta în cazul unor proiecte cu module interconectabile, este cea numită metode magice. Acestea sunt un set de metode standard, rezervate în limbajul de programare, care au o aceeaşi semnificaţie şi o aceeşi funcţionalitate în cazul oricăror clase definite de utilizator. Aceşte metode sunt autoapelate în anumite condiţii sau în cazul unor acţiuni externe.

Constructor si destructor

Metodele __construct() şi __destruct(), deşi pot fi numite magice doar prin modul de scriere, ele făcând parte din teoria programării orientate pe obiect, sunt metodele care se vor apela automat la crearea (instanţierea) respectiv distrugerea unui obiect aparţinând unei clase. De regula, în constructor se crează conexiuni, se setează variabile, se preiau variabile externe sau orice altă acţiune de iniţializare a elementelor clasei, pe când în destructor se face curăţenie printre aceste elemente, se închid eventualele conexiuni sau se şterg fişiere.


class math
{
protected $a;
protected $b;

public function __construct($x, $y)
{
$this->a = $x;
$this->b = $y;
}

public function add()
{
return $this->a + $this->b;
}

public function multiply()
{
return $this->a * $this->b;
}

public function __destruct()
{
unset($this->a);
unset($this->b);
}
}

$math = new math(3, 8);
echo $math->add();
unset($math);
?>

Constructorul va fi astfel apelat în momentul creării obiectului folosind operatorul new iar destructorul va fi apelat în la apelul lui unset() asupra obiectului în mod expicit sau în mod implicit la terminarea execuţiei scriptului, daca nu s-a făcut altfel.

Serializare şi deserializare

Serializarea este procesul de a liniariza o variabilă de orice tip într-una de tip string, cu scopul de a pastra informaţiile din interiorul ei(precum si tipul/tipurile de date) şi pentru a le transmite la distanţă fără pierdere de informaţii. Deserializarea este, evident, procesul invers. Daca în cazul unui vector rezultatul serializării este un string ce conţine în ordine şi pe nivele elementele acestuia, în cazul claselor se oferă posibilitatea de a alege ce date să se pastreze sau să se porteze. Pentru acest lucru au fost create două metode magice care vor fi apelate automat la apelul serializării sau a deserializării: __sleep() şi __wakeup().


class math
{
protected $a;
protected $b;

public function __construct($x, $y)
{
$this->a = $x;
$this->b = $y;
}

public function add()
{
return $this->a + $this->b;
}

public function multiply()
{
return $this->a * $this->b;
}

public function __sleep()
{
return array('a', 'b');
}

public function __wakeup()
{
echo 'a=' . $this->a . '; b=' . $this->b;
}

public function __destruct()
{
unset($this->a);
unset($this->b);
}
}

$mathAdd = new math(3, 8);
echo $mathAdd->add(); /* va afisa 11 */
$tmpData = serialize($mathAdd);

$mathMultiply = new math(0, 0);
$mathMultiply = unserialize($tmpData);
echo $math->multiply(); /* va afisa 24 */
?>

De menţionat este că la apelul unserialize() şi implicit a lui math::__wakeup() scriptul va printa valorile primite de la prima instanţiere a clasei.

String

Există şi o metodă simplă, numită __toString() care va fi apelată la fiecare apel al lui echo, print sau încercare de folosire a obiectului ca un string.


class hello
{
protected $foo;

public function __construct($bar)
{
$this->foo = $bar;
}

public function __toString()
{
return "Hello " . $this->foo;
}
}

$hi = new hello('george');
echo $hi; /* va tipari "Hello george" */

?>

O altă metodă de transmitere a datelor între obiecte, posibil mai convenabilă decât serializarea şi deserializarea, poate fi făcută cu ajutorul funcţiei var_export() şi a metodei magice __set_state(). var_export() va returna un string care va conţine, fie valoarea numerica (în cazul variabilelor scalare de tip numeric), fie o valoare de tip string (cazul variabilelor string), fie stringul care ar crea un vector în cazul acestora, fie valoarea returnată de metoda magica __set_state() în cazul obiectelor. Această metodă magică a fost introdusă odată cu versiunea 5.1.0 a PHP.


class A
{
public $var1;
public $var2;

public static function __set_state($an_array)
{
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

eval('$b = ' . var_export($a, true) . ';');
// $b = A::__set_state(array(
// 'var1' => 5,
// 'var2' => 'foo',
// ));

?>

Autoîncărcarea

Deşi nu este o metodă, funcţia __autoload() poate fi de mare ajutor atunci când aplicaţia dispune de un numar considerabil de clase care nu sunt folosite toate în acelaşi timp. Astfel, aceasă funcţie se va apela şi va include, dacă este nevoie, un fişier care va conţine definiţia clasei, în momentul instanţierii unui obiect. În scenariul de faţă, este de preferat ca toate definiţiile clasei să fie situate într-un acelaşi director, iar fiecare clasă situată într-un fişier separat al cărui nume sa fie identic cu al clasei.


function __autoload($className)
{
if (!class_exists($className))
{
include("includes/classes/" . $className . ".php");
}
}

Se evită in acest fel încărcarea tuturor claselor existente în aplicaţie şi îngreunarea acesteia luând în considerare presupunerea ca nu toate clasele vor fi folosite în oricare acţiune a aplicaţiei, prin faptul ca o clasa va fi încarcată doar dacă este nevoie si doar atunci când este nevoie.

Paginare datelor este un mijloc eficient de a reduce datele raportate unui utilizator la o secţiune de interes local în ideea de a economisi timp de execuţie, spaţiu de afişare şi se a crea nişte raportări prietenoase. Exemplul cel mai simplu în reprezintă afişarea unor produse dintr-un magazin online pe … pagini, lucru care are avantajul că pe de partea clientului nu încarcă excesiv pagina utilizatorului (un magazin poate avea câteva sute de produse, poate chiar mii) iar pe partea serverului nu solicită nici baza de date dar nici procesările făcute după ce un set de date a fost returnat aplicaţiei, toate acestea făcându-se asupra unui set restrans de date.

Introdus in versiunea 1.6 a Zend Framework, modulul Zend_Paginator, aşteptat încă din versiunea 0.9, se vrea a fi o componentă flexibilă pentru paginarea colecţiilor de date şi prezentarea lor către utilizatori. Principalele avantaje ale acestui modul sunt posibilitatea de a pagina orice set de date, nu doar cele provenite din baza de date, aduce si prelucreaza doar setul de date care urmează a fi afişat nu asupra tuturor datelor, plus că fiind felxibil nu limitează programatorii doar la folosirea lui şi într-un anume mod, dar oferă totodată posibilitatea de folosirea a lui din alte componente ale framework-ului precum Zend_View sau Zend_Db.

Folosirea paginatorului este relativ simplă, şi se foloseşte de ideea că pentru a putea pagina un set de date, în orice format ar fi el, este nevoie de un adaptro specific pentru a putea interacţiona cu acele date. Astfel, pentru a putea pagina un vector, se poate folosi un array simplu din PHP, pentru a pagina un set de date returnate în urma unei interogări a bazei de date se foloseşte o instanţă a Zend_Db_Select, iar pentru a pagina un iterator se va folosi o instanşă a acestei clase din SPL. Pentru a începe folosirea paginatorului se poate instanţia acesta folosind adaptorul dorit, sau se poate folosi metoda statică factory():


$array = array(‘Luni’, ‘Marti’, ‘Miercuri’, ‘Joi’, ‘Vineri’, ‘Sambata’, ‘Duminica’);
$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_Array($array));
$paginator = Zend_Paginator::factory($array);

În acest moment paginatorul are nevoie de o referinţă pentru a putea determnia şi prelucra secţiunea care va fi afişată utilizatorului, şi anume pagina, informaţie care de regula se stochează într-un parametru al URL-ului(implicit va fi considerată pagina 1). Totodată se poate specifica şi numărul de elemente care vor apărea intr-o pagină, acest număr este implicit 10.


$paginator->setCurrentPageNumber($this->_request->getParam(‘page’));
$paginator->setItemCountPerPage(20);

În final paginatorul se atribuie unei variabile din partea vizuală a aplicaţiei …


$this->view->paginator = $paginator;

iar apoi va fi afişată


paginator as $element): ?>


Daca dorim paginarea unor date provenite din baza de date, cu siguranţă că va fi mai eficient ca interogarea făcută către baza de date să returneze doar acele date din pagina care ne interesează. Pentru acest lucru vom instanţia paginatorul folosind un obiect de tipul Zend_Db_Select, care va conţine o instrucţiune select personalizată pentru nevoile noastre.


class My_Model
{
public static function getCategoryList($category_id, $page = 1)
{
$databaseAdaptor = Zend_Registry::get('db');
try
{
$select = new Zend_Db_Select($databaseAdaptor);
/*$select = $databaseAdaptor->select();*/
$select->from('products', array('id', 'name', 'price'))
->where('category_id = ?', $category_id)
->order('name asc')
;

$paginator = Zend_Paginator::factory($select);
$paginator->setCurrentPageNumber($page);
$paginator->setItemCountPerPage(10);

return $paginator;

}
catch (Zend_Exception $ex)
{
Zend_Debug::d ump($ex);
return null;
}
}
}

Am creat asadar un model care va returna din baza de date toate produsele dintr-o anumită categorie, sortate după nume, folosind un obiect Zend_Db_Select instanţiat folosind un adaptor pentru baza de date, care a fost preluat din registru. Rezultatul unei astefel de abordări poate fi procesat într-un controller după cum urmează:


class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
Zend_Loader::loadClass('My_Model');
$this->view->paginator = My_Model::getNewsletterList($this->_request->getParam('category_id'), $this->_request->getParam('page'));
}
}

Un alt aspect important al paginării este capacitatea acestei componente de a genera un nagivator printre “paginile” astfel determinate ale paginării, deci în ultimă instanţă posibilitatea de a avea acces secvenţial la tot setul de informaţii. Zend_Paginator furnizeată unul chiar interesant, datorită facilităţilor ce le oferă.


echo $this->paginationControl($this->paginator, 'Sliding', 'pagination_control.phtml');

Deşi ultimii doi parametri sunt opţionali, iar controlul ar putea funcţiona perfect fără aceste două informaţii, aceştia pot influenţa foarte mult modul în care acest index al navigării este construit. Ele se referă la, şi influenţează modul în care navigatorul generat va arăta şi comporta. Vom considera, pentru exemplificare, că navigatorul generat de Google la o căutare ar fi generat chiar de către Zend_Paginator.

Google Slider

Cel de-al doilea parametru controlează ce se întamplă daca acţionăm linkul “Precedentă” sau “Următoarele” şi poate avea urmatoarele valori

  • All caz în care va afişa toate paginile existente, lucru util pentru momentele când numărul paginilor rezultate este relativ scăzut
  • Elastic caz în care paginile se lărgesc şi se contractă în funcţie de poziţia în paginare şi numărul de pagini – gen Google
  • Jumping caz în care pe măsură ce utilizatorul trece de la o pagină la alta, pagina curentă se muta catre finalul unui interval de pagini, la finalul caruia va continua cu un interval nou
  • Sliding caz în care pagina curentă va fi afişată în centrul intervalului de pagini afişat, sau cel mai aproape posibil (gen Yahoo!); acesta este valoarea implicită

Cu toate acestea însă programatorul nu este restricţionat la acest set de posibilităţi, oferindui-se posibilitatea de a-si crea singur porpiul paginator. Pentru acest lucru sunt disponibile o serie de metode predefinite:

  1. first() — numărul primei pagini
  2. firstItemNumber() — numărul primei înregistrari din pagină în setul general de date
  3. firstPageInRange() — numărul primei pagini din setul curent
  4. current() — numărul paginii curente
  5. currentItemCount() — numărul de elemente afişate pe pagina curentă
  6. last() — numărul ultimei pagini
  7. lastItemNumber() — numărul ultimei înregistrari din pagină în setul general de date
  8. lastPageInRange() — numărul ultimei pagini din setul curent
  9. next() — numărul paginii următoare
  10. pageCount() — numărul total de pagini
  11. pagesInRange() — paginile aflate în setul de pagini
  12. previous() — numărul paginii precedente
  13. totalItemCount() — numărul total de elemente

Prin setul curent de pagini, ne-am referit la paginile vizibile la o afişare.

Am observat de-a lungul timpului că o bună parte a începătorilor în ale programării PHP au o mare problemă în a înţelege şi a folosi corect facilităţile oferite de… ghilimele şi apostroafe.

Diferenţa esenţială între cele două modalităţi de a afişa stringu-uri este la interpretarea conţinutului. Vom considera următoarele exemple:

Exemplul 1

echo 'foo';
echo "bar";

Exemplul 2

$str = 'foo bar' . "\r\n";
echo "Un string frumos afisat este: $str";

Exemplul 3

echo 'link html';
echo "link html";

Exemplul 4

$mysql = "select id, name, age from people where name like 'george%'";
$mysql = 'select id, name, age from people where name like \'george%\'';

Aşadar, diferenţa esenţială este la modul de interpretare a conţinutului aflat între cele două simboluri grafice şi anume în cazul ghilimelelor se interpretează, iar în cazul apostroafelor nu se interpretează. Astfel, orice string delimitat de apostroafe care va conţine numele unei variabile va printa numele variabilei incluzând semnul dolar din faţa acestia, pe cand un acelaşi string delimitat de ghilimele va printa valoarea acelei variabile şi nu numele ei. De aici se poate deduce uşor ca în cazul printării unui string simplu se preferă utilizarea apostroafelor metodă care va fi mai rapidă decât cea cu ghilimele, în care interpretorul va încerca să gasească şi să înlocuiască posibilele variabile inserate de către programator (deci, timp mai mare de execuţie)
Este de observat şi faptul că în anumite cazuri este de păreferat folosirea ghilimelelor în detrimentul apostroafelor, sau invers, lucru care ar duce la o lizibilitate şi o coerenţă mai marită a codului sursă, plus că poate elimina câteva erori de parsare în cazul unor stringuri mai complexe. În exemplul 3 se poate observa cum folosirea de apostroafe pentru a printa un cod HTML este mai convenabil decat folosirea ghilimelelor, fapt ce ar determina ca oricăror atribute din tag-urile HTML să li se aplice metoda escape. Deasemeni, caz contrar, exemplu 4 arată cum un string ce ar reprezenta o interogare SQL ar fi mai uşor de citit şi înţeles dacă s-ar folosi ghilimelele.

Ghilimele magice

Ghilimelele magice, sau magic quotes, reprezină o funcţionlitate a limbajului PHP care presupune introducerea unui backslash (\) înaintea oricarui caracter apostrof, ghilimea, backslash şi NULL, procedeu cunoscut sub numele escape. Motivaţia pentru care s-a introdus această funcţionalitate a fost aceea de a ajuta programatorii incepători, sau neexperimentaţi de a preveni aşa zisele sql injections.
Controlul acestei facilităţi se face cu ajutorul unor directive din cadrul php.ini

  1. magic_quotes_gpc are efect asupra variabilelor provenite prin GET, POST, COOKIE, este setata implicit pe on şi nu poate fi modificată la în timpul excuţiei.
  2. magic_quotes_runtime în caz că este activată va avea efect asupra tuturor funcţiilor care returnează date din surse externe, provenite de la utilizator sau chiar şi din baze de date sau fişiereş implicit are valoarea off şi poate fi modificată ân timpul execuţiei.
  3. magic_quotes_sybase daca este activată va dubla orice apostrof cu un alt apostrof, în loc de backslashş totodată va suprascrie directiva magic_quotes_gpc; atenţie aşadar, având ambele directive activate, acestea vor determina ca doar apostroafele sa fie dublate de un alt rand de apostroafe, restul caracterelor (ghilimele, backslash, NULL) vor rămâne nemodificate.

Ghilimelele magice sunt activate implicit cu o instalare nouă de PHP şi cum efectul lor nu este vizibil întotdeauna, unii programatori nici nu sunt conştienţi de existenţa lor si de posibilele probleme care le pot cauza. De-a lungul timpului au existat mai multe critici aduse acestei facilităţi, lucru care a dus la considerarea ei ca fiind invechită, dintre care enumerăm:

  1. nu toate datele furnizate de catre utilizatorului unei aplicaţii web sunt menite a fi introduse într-o bază de date; ele pot fi stocate într-o sesiune sau afişate pe ecran, iar introducerea unui bachslash ar altera considerabil conţinutul acestor date
  2. nu toate datele introduse de către un utilizator sunt obţinute din surse aflate sub protecţia ghilimelelor magice; de exemplu o valoare poate fi obţinută de la utilizator, stocată în baza de date(deci sub influenţa ghilimelelor magice), apoi citită şi folosită intr-o alta operaţie sql unde ghilimelele magice nu au efect, aspect care ignorat de un programator ar putea avea consecinţe grave
  3. efectul de ghilimele magice se bazează pe folosirea funcţiei addslashes() care nu funcţionează corect pe string-urile Unicode, deci posibilitatea de a obţine un sql injection este ridicată (se recomandă în cazul inserărilor in baza de date folosirea funcţiilor de escape specifice, gen mysql_real_escape_string())
  4. adaugarea de ghilimele magice şi scoaterea lor atunci cand se cere poate fi, în funcţie de aplicaţie, o operaţie costisitoare ca timp, deci preferabil de evitat

În versiunea 5 a PHP ghilimelele magice au fost considerate depăşite si au fost marcate pentru eliminare odata cu versiunea 6 a limbajului de programare.

Vectorii, numiţi in engleză array, reprezintă cea mai avansată metodă de stocare a datelor în PHP. Sunt cele mai flexibile structuri de date: ele permint indecşi numerici sau alfanumerici, dar şi combinaţii; pot avea indecşi auto-incrementabili şi pot fi folosiţi ca stive, cozi, mulţimi, vectori uni, bi sau multi-dimenisonali şi pot stoca practic orice tip de dată. Este şi motivul pentru care în nucleul php există aproximativ 70 de funcţii definite pentru a uşura lucrul cu vectorii.

Aşadar aceşti vectori sunt o colecţie ordonată de obiecte numite generic elemente. Oricare dintre aceste elemente are o cheie unică în vector precum şi o valoare. Vectorii pot fi creaţi in 2 feluri, fie apeland functia array simplu, sau cu parametrii caz în care aceştia sunt atribuiţi vectorului.

[code lang="php"]
$arr = array();
$arr = array('a' => 1, 'b' => 2, 'c' => 3);
$arr = array(1 => 'a', 2 => 'b', 3 => 'c');
$arr = array(1, 2, 3);
[/code]

Primul apel va crea un vector gol, cel de-al doilea un vector cu indecşi alfanumerici, al 3-lea cu indecşi numerici, iar pentru cel din urmă am furnizat doar valorile elementelor, pentru care indecşii de vor atribui automat prin autoincrementare.

Afisarea vectorilor

Spre deosebire de tipurile de date scalare(int, string, float) care pot fi afişate folosind funcţia echo, pentru vectori aceasta prezintă cateva neajunsuri la afişarea datelor. De exemplu, în timpul unui debug poate fi esenţial să avem informaţii nu doar despre datele aflate în elemnte, dar şi tipul lor de date, pe oricare din nivelele existente. Pentru a preîntâmpina această problemă PHP furnizează 2 funcţii de afişare recursivă a informaţiilor dintr-un array:
[code lang="php"]
$array = array(1, 2, 'foo');
print_r($array);
var_dump($array);
[/code]
Acest cod va produce următorul text:
[code]
Array
(
[0] => 1
[1] => 2
[2] => foo
)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
string(3) "foo"
}
[/code]

Observaţi cum, deşi ambele afişează elementele vectorilor, doar var_dump afişează şi tipul de dată al elementului respectiv. Mai mult, doar var_dump este capabil sa afişeze informaţiile despre mai mult de o variabiă, iar print_r are capacitatea de a trimite rezultatul către o variabilă prin specificarea celui de-al doilea parametru optional.

Începem prin a propune ceva usor şi … teoretic.

Standardele de codare, sau coding styles, reprezintă un set de reguli care trebuiesc aplicate atunci când un programator îşi scrie propriul cod. Aceste reguli sunt făcute pentru a uşura comunicarea într-o echipă relativ mare de programatori care lucrează la acelaşi proiect, dar totodată asigură că orice viitor programator nou va putea înţelege intr-un timp cât mai scurt ideile codului.

Majoritatea companiilor mari au deja un standard de codare stabilit pe care îl impun noilor angajaţi. De altfel pentru fiecare limbaj de programare exista un set de astfel de reguli oarecum standardizate, cum ar fi C++, PHP, C#, Java, Python.

Chiar şi ca free-lancer este bine să-ţi creezi propriul stil de codare, pentru a preveni neplacerile cauzate de revenirile la un cod pe care nu ai mai lucrat un timp îndelungat.

Preferaţi un anume standard? De ce?

Salut!

Începem cu celebrul “Hello world” pentru a vă saluta şi pentru a vă dori o experienţă cât mai plăcută cu noi.

[code lang="php"]
echo 'Hello World!';
[/code]

sau

[code lang="sql"]
SELECT 'Hello World' AS greeting;
[/code]