Un punct de reper pentru a descoperi un programator bun, indiferent de limbajul de programare pe care îl utilizează, este abilitatea acestuia de a aplica tehnici cunoscute de design al aplicaţiei. Design patterns(sau proiectarea modelelor) sunt un un set de soluţii ce pot fi aplicate la diverse probleme ce se întâlnesc frecvent în cadrul programării orientate pe obiect.
În teorie, aceste modele nu au legătură cu codul scris de un programator. Sunt niște soluţii de eficientizare a problemelor des întâlnite, nişte indicaţii pe care programatorul trebuie să le transpună în limbajul de programare pe care îl foloseşte. Ne vom referi în continuare la aceste modele legat de limbajul PHP, modele care deşi pot fi implementate folosind şi programarea procedurală, ele sunt evidenţiate mai bine cu ajutorul programării orientate pe obiect.
Singleton
Modelul Singleton este probabil cel mai simplu model. El este făcut pentru a permite accesul la o singură resursă care nu va fi niciodată duplicată, dar care trebuie făcută disponibilă în orice moment al execuţiei aplicaţiei. Implementarea unui Singleton trebuie să satisfacă cele două condiţii de acces global şi instanţiere singulară a resursei respective. Are nevoie de un mecanism de acces la class Singleton fără a instanţia un obiect şi un mecanism de a păstra informaţia asupra resursei ce urmează a fi folosită. Astfel acest model poate fi cel mai uşor implementat prin crearea unei clase ce va conţine o metodă care va crea o nouă instanţă a clasei, dacă aceasta nu exista deja, iar dacă există o va returna pe aceasta. Pentru a fi siguri că acea clasă nu va fi instanţiată în alt fel, constructorul este declarat protejat. Exemplul cel mai simplu este acela în care se pune problema existenţei unei singure conexiuni la baza de date:
{
private static $_singleton;
private $_connection;
protected function __construct()
{
$this->_connection = mysql_connect(SERVER, USER, PASSWORD);
}
public static function getInstance()
{
if (is_null(self::$_singleton))
{
self::$_singleton = new database();
}
return self::$_singleton;
}
}
$cnx = database::getInstance();
Aşadar constructorul a fost declarat protejat pentru a controla accesul la el şi de a da posibilitatea apelării lui doar din interiorul clasei. Acest lucru este făcut cu ajutorul metodei statice getInstance, care verifică la fiecare apel al ei dacă există definit membrul static $_singleton, caz în care îl va returna, sau va încerca să creeze unul nou. Odată creat, metoda getInstance() nu va mai încerca să creeze unul nou ci-l va retuna pe cel creat tot timpul.
Factory
Modelul Factory se foloseşte în scenariile în care există o clasă generică (fabrica) care are posibilitatea de a crea o instanţă a una sau mai multe clase specializate în rezolvarea unei aceleaşi probleme dar în diferite moduri. Un astfel de exemplu îl reprezintă stocarea datelor de configurare într-o aplicaţie. Datele de configurare, precum credenţialele pentru conectarea la baza de date, sau căile de acces la diverse directoare, pot fi stocate în mai multe feluri: în fişiere XML, in fişiere INI sau chiar în baza de date. Astfel putem crea un mecanism care să returneze un obiect ce va şti să lucreze cu un anume mod de stocare a acestor date de configurare.
{
const STORE_IN_INI = 1;
const STORE_IN_DB = 2;
const STORE_IN_XML = 3;
public static function factory($type = self::STORE_IN_INI)
{
switch ($type)
{
case self::STORE_IN_INI:
return new configuration_ini();
case self::STORE_IN_DB:
return new configuration_db();
case self::STORE_IN_XML:
return new configuration_xml();
default:
throw new Exception(‘Tip de stocare necunoscut’);
}
}
}
Este evident faptul că toate cele 3 clase specializate de tratare a fișierelor de configurare (ini, xml, db) trebuiesc definite şi implementate, un avantaj fiind definirea lor conform unei clase abstracte. Apelarea “fabricii” se face după cum urmează:
Registry
Modelul Registry este un model Singleton mai evoluat, în sensul că permite stocarea mai multor resurse, ca într-un registru. Un exemplu ar fi acela în care, deşi avem conexiunea stabilită către baza de date printr-un Singleton, şi prin această conexiune se fac toate interogările, există posibilitatea ca din aplicaţie să fie nevoie de conexiunea în paralel către o alta bază de date pentru a efectua şi acolo diverse operaţiuni. Cu un simplu Singleton nu s-ar fi putut realiza aşa ceva însă cu un Registry acest lucru este posibil. Un astfel de Registry va trebui să implementeze metode de adăugare, verificare a existenţei şi de returnare a informaţiilor cerute.
{
private static $_register;
public static function add(&$element, $name)
{
$name = strtolower($name);
self::$_register[$name] = $element;
}
public static function exists($name)
{
$name = strtolower($name);
if (array_key_exists($name, self::$_register))
{
return true;
}
return false;
}
public static function &get($name)
{
$name = strtolower($name);
if (self::exists($name))
{
return self::$_register[$name];
}
else
{
throw new Exception(‘Elementeul cerut nu exista in registru.’);
}
}
}
O folosirea a cestul model este următorul cu precizarea ca în acest exemplu clasa database nu este un Singleton:
registry::add($db, ‘dbCnx’);
/*
verificarea conexiunii
*/
if (registry::exists(‘dbCnx’))
{
$db = registry::get(‘dbCnx’);
}
Model-View-Controller
Spre deosebire de celelate modele discutate anterior, Model-View-Controller(denumit şi MVC) este un model destul de complex. Scopul lui este de a oferi o metodă de separare dintre logica aplicaţiei (model), modului de afişare (view) şi structura decizională (controller), aplicaţiile MVC fiind astfel usor de modificat atunci când se doreşte modificarea doar a modului de afişare sau a modului în care este tratată o cerere.
Logica unei astfel de aplicaţii este următoare: o cerere este făcută către aplicaţie şi este apelat controller-ul care va decide cum va trata cererea. Controller-ul va chema o clasă din Model, care efectiv va efectua interogări către baza de date, prelucrările necesare ale datelor sau orice alte operaţiuni necesare. Rezultatul, de regulă un set de date, va fi întors către Controller care va transmite aceste date părţii vizuale a aplicaţiei(View) unde deja există o structură de afişare a datelor ce tocmai au fost primite. Avantajul enorm al acestui model este separarea clară între cele 3 compomente şi uşurinţa cu care se pot extinde aplicaţiile dezvoltate pe acest model.

Marfa articol, maestre. Am implementat si eu o clasa care sa realizeze conexiunea la BD in ultimul proiect la care lucrez dar nu m-a dus capul sa o fac asa de eleganta
Totusi am cateva mici obiectii / nelamuriri:
1. la Singleton ai spus ca, “constructorul este declarat protejat” dar l-ai facut private
2. Eu am creat si destructor explicit la clasa care face conexiunea la BD in care inchid conexiunea. Da, stiu, PHP-ul ar trebui sa aiba un garbage collector care sa se ocupe automat de asa ceva, dar, mi se pare mai elegant sa ii dau eu un mysql_close($link). Acest lucru ofera totusi posibilitatea inchiderii conexiunii la baza de date inaintea terminarii scriptului PHP. Ar fi util cand avem de-a face cu mai multe baze de date simultan pentru a mai elibera din resurse.
3. Nu ma prind ce face acel ampersant din fata functiei get de la modelul registry
Nici nu tin minte sa fi vazut vreodata asa ceva…
PS: fa si tu ceva cu smyle-urile alea ca arata naspa in Firefox cel putin.
PS2: Nu ar strica o optiune de editare a comment-urilor, ca sa pot macar sa scot smyle-urile… Din pacate m-am obisnuit cu ele de pe mess…
PS3: Scuze de double post dar, daca nu il pot edita pe cel anterior…
Oricum, spor la scris articole in continuare. Mai astept si altele la fel de interesante.
Salut,
Multumesc pentru aprecieri si te mai astept cu altele la fel cum te mai astept si cu obiectii, nelamuriri sau chiar propuneri de subiecte.
1. Asa e, mia cupla, am modificat si in articol sa nu mai existe confuzie.
2. PHP are si el un garbage collector, poate nu in sensul in care il stii din Java, insa el exista si este unul destul de eficient si optimizat. El va face curatenie de fiecare data cand este cazul: atunci cand ii spui tu, cand iesi dintr-o functie sau cand se termina executia scriptului. Daca nu realizezi aplicatii cu consum mare de memorie recomandarea mea ar fi sa lasi treaba de curatenie in seaman PHP-ului. Iti dau si un exemplu referitor la conexiunea de MySQL: presupunand ca tu nu ai apelat mysql_close() la finalul scriptului, PHP nu va inchide conexiunea imediat, ci o va pastra intr-o stare de asteptare pentru scurt timp, timp in care daca se va mai primi o cerere de conectare catre baza PHP o va furniza pe cea existenta, economisind astfel ceva timp de executie.
3. Unpercentul din fata metodei se refera la faptul ca acea metoda va returna referinta. Daca nu am fi inclus acel unpercent metoda ar fi returnat o copie a obiectului si nu obiectul in sine, ceea ce nu ar fi fost corect in cazul de fata.
Multa bafta!
@2. Am prins ideea. You have a point. Am sa tin cont de asta in viitor.
@3. Stiu ca & = referinta (asa e si in C#) dar nu stiam ca se poate folosi decat pentru parametrii unei functii. Oare merge si in C# folosit asa?
Propunere de tema… Pai, hmmm… Ceva de genul: cum sa protejezi un site SQL injecturi si HTML injecturi.
Spor in continuare.