-
JavaScript si PHP suporta atat functii lambda cat si closures. Dar termenii sunt putin intelesi in ambele libaje de programare si de multe ori sunt confundati.
Functii Lambda
Mai sunt numite si functii anonime. Acestea se refera la functii care pot fi apelate fara sa fie neaparat legate de un identificator. Unul din scopurile lor este de a fi pasate ca argumente. Numele de Lambda li se trage de la Alonzo Church, inventatorul lambda calculus in 1936. In lambda calculus toate functiile sunt anonime.
JavaScript
In JavaScript functiile lambda fac parte din setul de baza si reprezinta metoda preferata de creare a unei functii.
De exemplu:
1var add = function (a, b) { 2 return a + b; 3} 4alert(add(1, 2)); // 3
Functiile lambda sunt folosite aproape in orice context cand vine vorba de JavaScript, un exemplu este:
1window.onload = function (e) { 2 alert('Pagina s-a incarcat!'); 3}
PHP
In PHP, functiile lambda au fost introduse de la versiune 4.0.1 folosind create_function. In versiunea 5.3+ a fost adaugata si sintaxa similara cu JavaScript, un mod mult mai lizibil si elegant de a definii o functie.
Asta inseamna ca in PHP exista doua moduri de a genera o functie lambda:
1// PHP 4.0.1+ 2$add = create_function('$a, $b', 'return $a + $b;'); 3 4// vs. 5 6// PHP 5.3+ 7$add = function ($a, $b) { 8 return $a + $b; 9}; 10 11echo $add(1,2); // 3
Functiile lambda pot fi folosite ca parametru pentru alte functii, cum ar fi usort:
1$array = array(4, 3, 5, 1, 2); 2usort($array, function ($a, $b) { 3 if ($a == $b) { 4 return 0; 5 } 6 return ($a < $b) ? -1 : 1; 7});
Chiar mai mult, PHP 5.3+ permite apelarea unui obiect ca o functie anonima:
1class test { 2 function __invoke($a) { 3 echo $a; 4 } 5} 6$a = new test(); 7$a('test'); // 'test'
Closures
Notiunea de closure este notiunea cu adevarat neinteleasa dintre cele doua. In general confuzia apare pentru ca implementarea de cloasure poate presupune si functii lambda. Un closure se refera la capacitatea unei functii/obiect de a accesa mediul in care aceasta a fost creat(a) chiar daca executia functiei parinte s-a terminat. Cu alte cuvinte functia/obiectul intors de un cloasure pastreaza mediul in care a fost definita.
In JavaScript notiunea de closure face parte din arsenalul de baza, pentru ca limbajul nu are la baza un model obiectual traditional ci unul bazat pe prototype si functii. Dar JavaScript mai are si cateva reminescente, cum ar fi faptul ca poti folosi “new” pentru a construi un obiect pe baza unei functii care joaca roul de clasa. In PHP este mai degraba o noua posibilitate de abordare a problemelor, PHP facand parte din familia de limbaje cu model obiectual traditional.
JavaScript
In JavaScript notiunea de closure este foarte folosita, iar popularitatea se datoreaza faptului ca JavaScript nu este un limbaj obiectual traditional, ci unul functional, bazat pe mostenire prototype.In JavaScript nu exista notiunea de Public, Private si Protected, exista doar Public si Private iar obiectele pot mostenii unele de la altele, fara sa foloseasca clase.
O alta problema este mediul (scope), care in mod implicit este cel global. Prin closure aceste probleme pot fi rezolvate intr-un mod elegant:
1var closure = function () { 2 var sum = 0; 3 return { 4 add: function (nr) { 5 sum += nr; 6 }, 7 getSum: function () { 8 return sum; 9 } 10 } 11}(); 12 13closure.add(1); 14closure.add(2); 15console.log(closure.getSum());
In exemplul de mai sus, sum este o proprietate privata iar aceasta teoretic, putea fi accesata si modificata doar din functia closure. Partea interesanta este ca parantezele de la finalul definitiei de functiei semnifica faptul ca aceasta functie se va si executa si deci va intoarce rezultatul care este un obiect. In acest moment functia initiala nu mai exista decat pentru a servi obiectul intors, incapsuland astfel variabila privata.
Desi functia si-a terminat executia, prin intermediu acestul closure obiectul returnat poate accesa variabilele definite in interiorul functiei, pentru ca este mediul in care a fost creeat.
Problema devine mai interesanta atunci cand o functie intoarce o alta functie:
1var counter = function () { 2 var counter = 0; 3 console.log('in closure'); 4 return function () { 5 console.log('in functia anonima'); 6 return ++counter; 7 }; 8}; 9var counter1 = counter(); 10 11console.log(counter1()); // 1 12 13var counter2 = counter(); 14console.log(counter2()); // 1 15console.log(counter1()); // 2
Output-ul va fi:
1in closure 2in functia anonima 31 4in closure 5in functia anonima 61 7in functia anonima 82
Ce se intampla de fapt este ca prima functie se executa si intoarce o functie anonima care inca mai poate accesa mediul in care a fost creata. Dupa parerea mea de aici vine confuzia dintre closures si lambda functions, pentru ca o functie intoarce o alta functie.
Diferenta dintre exemple este ca in primul exemplu functia initiala de closure se executa imediat, iar in al doilea exemplu se poate vedea ca atunci cand counter se executa intoarce un rezultat, care este de fapt o definitie de functie, care la randul lui poate fi executata. Evident si acest exemplu poate fi adaptat sa se comporte precum cel precedent folosind paranteze la final.
PHP
Cum spuneam si mai sus, in PHP notiunea de closure nu este la fel de importanta ca in JavaScript.
Daca functiile lambda sunt disponibile in limbaj incepand cu versiunea 4, closure au aparut de abea dupa PHP 5.3+
Datorita mediului (scope) de executie care este de tip block in PHP se realizeaza o incapsulare mai buna dar si mai putin flexibila fata de JavaScript. Practic in PHP trebuie specificat cu ajutorul instructiunii use ce anume va putea accesa functia anonima din closure-ul care si-a terminat executia.
1function closure () { 2 $c = 0; 3 return function ($a) use (&$c) { 4 $c += $a; 5 echo $a . ', ' . $c . PHP_EOL; 6 }; 7} 8 9$closure = closure(); 10 11$closure(1); 12$closure(2);
Spre deosebire de JavaScript in PHP nu se pot realiza closure care sa intoarca un obiect, sau mai bine zis obiectul nu poate fi legat de mediul in care a fost creat, decat sa zicem, daca nu se trimit parametrii la constructor prin referinta, metoda nu foarte eleganta care nu vad in ce scenariu ar avea neaparata nevoie de closure.
Ca o paralela la exemplele de la JavaScript, in loc de parantezele “()” de la finalul functiei, in PHP pentru a executa functia imediat dupa definire se pot folosii call_user_func() sau call_user_func_array():
1$closure = call_user_func(function () { 2 $c = 0; 3 return function ($a) use (&$c) { 4 $c += $a; 5 echo $a . ', ' . $c . PHP_EOL; 6 7 }; 8}); 9 10$closure(1); 11$closure(2);
-
Dupa cum spuneam intr-un blog anterior, cand Zend a lansat noua certificare ZCE 5.3 am primit un cod de discount pentru voucherul de certificare, valabil pana la finalul anului 2010. Am vrut sa profit, asa ca in ultima saptamana din an am cumparat voucherul.
Aveam deja experienta de la certificarea ZCE 5, despre care am vorbit la momentul respectiv.
Am vrut ca pana la finalul concediului, adica pe 7-I sa o dau.
Termenul a fost cam scurt, am avut teoretic aproape doua saptamani sa ma pregatesc, dar pentru ca acestea erau in preajma sarbatoriilor timpul a fost de fapt mult mai scurt.
Zend PHP5 Certification Study Guide – 2nd Edition
Am inceput studiul cu Zend PHP5 Certification Study Guide – 2nd Edition. Cartea chiar daca nu inglobeaza noiile facilitati 5.3 nu este depasita. Pentru ca nu era prima data cand o citeam deja intr-o buna masura a fost mai mult o recapitulare. Am incercat ca pentru fiecare capitol sa fac un exemplu care sa probeze functionalitatea si unul ca sa probeze cazurile pentru care nu se aplica. Cu toate acestea in 4 zile am reusit sa parcurg intreaga carte.
Ca o sugestie, pentru partea de stream-uri si SPL de exemplu, unde este destul de greu de studiat direct din manual ghid-ul mi se pare un inceput bun.
Pentru ca pana la urma cartea este un ghid, in timp ce am citit cartea m-am uitat in capitolele corespunzatoare din manualul de pe php.net pentru o imagine mai larga.
Mock tests
Inainte sa termin cartea am incercat sa fac un mock test pentru PHP5 si spre marea mea surprindere rezultatul a fost “Excellent”. Mock testele le am de cand am dat ZCE 5, iar pentru ca exista o frecventa destul de mare cu care se repetau intrebariile nu am folosit decat 3 atunci. Si acum am facut doar doua din acelasi motiv. Testele sunt foarte utile pentru partea de PHP 5 pentru ca dupa parerea mea, asa cum era si in descrierea lor, acestea sunt mai complicate de multe ori decat examenul in sine. Totusi nu faceti foarte multe, mai ales daca rezultatele la primele sunt slabe pentru ca va pot induce intr-o falsa incredere din pricina intrebariilor repetitive.
Zend PHP 5.3 Study Guide
Cand am terminat cartea am trecut la ghidul gratuit Zend PHP 5.3 Study Guide, care se poate decarca de pe pagina cu detaliile legate de certificare, partea dreapta. Ghidul este in versiune beta si se simte. Cred ca toti cei care vorbesc despre el spun ca are multe bug-uri, si pana la urma este adevarat. Unul dintre cele mai amuzante mi se pare la pagina 109, intrebarea 12, raspunsul la intrebare este D… care nu este afisat in pagina. Dar parerea mea este ca acolo unde sunt bug-uri acestea vor fi gasite relativ usor si nu vor induce in eroare.
Se simte mult mai tare ca acesta este un ghid decat la cartea precedenta, este mult mai sumar si abstract si te obliga sa studiezi manualul.
La finalul fiecarui capitol sunt intrebari, nu am avut rezultat 100% decat la doua capitole. Intrebariile sunt dificile, mai dificile decat la examen in sine dupa parerea mea. Cu toate astea cititi fiecare intrebare cu atentie pentru ca asa va fi si la examen.
Ca sa trec prin tot ghid-ul mi-a mai luat inca 2 zile pentru ca eram incins deja de la cartea precedenta.
Ziua dinainte de examen
Am citit pe blog-ul lui Lorna “lornajane” Mitchell ca inainte de examen e bine sa recapitulezi cateva subiecte mai delictate. Eu in ultima zi am inceput sa recapitulez lucrurile care necesita mai multa memorie decat intelect, cum ar fi zeciile de functii pentru string-uri si array-uri. De asemenea cred ca merita repetat si SPL.
Examenul
Dupa nu foarte mult timp de studiu a venit si momentul examenului.
La fel ca si data trecuta, m-am programat pe Internet cu o zi inainte si m-am prezentat in centrul Pearson VUE.
Examenul in sine nu mi s-a parut mult mai dificil decat cel anterior. Mi se pare ca se pune mai mult accent pe notiuni mai high level de OOP si SPL decat in cel precedent. Stilul intrebariilor mi se pare similar, poate un pic mai multe intrebari “type in”, dar asta se poate sa fie doar norocul meu pentru ca intrebariile sunt selectate dinamic dintr-o serie de intrebari de diferite grade de dificultate.
Timpul de 90 de minute a fost suficient pentru a parcurge toate intrebariile cu atentie si a face review la care nu eram sigur. Data trecuta am terminat cu aproape jumatate de ora inainte, acum nu mi-au mai ramas decat 10 min, poate pentru ca am incercat sa nu ma grabesc de loc.
MULTA ATENTIE! Este foarte important sa citesti intrebariile cu antetie si sa le recitesti de cate ori este nevoie pana cand esti sigur ca ai inteles ce se cere. Unele intrebari sunt formulate mai ciudat si pot induce foarte usor in eroare. Nu intra in panica, daca ai dubii poate trebuie sa marchezi intrebarea pentru review si sa te intorci la ea la final.
Eu personal la inceputul examenului am emotii si primele intrebari le marchez pentru review pentru ca nu reusesc sa ma concentrez suficient.
Fata de acum 2 ani, cand lucram mult mai mult cu PHP brut si mai erau si unele servere de PHP 4 anul trecut am lucrat mai mult cu framework-uri open-source. Asta poate fi un dezavantaj pentru ca nu mai lucrezi atat de mult direct cu functii de core. Dar fata de prima certificare recunosc ca am studiat mult mai putin, probabil si experienta isi spune cuvantul dar si faptul ca ocazional mai rasfoiesc vechiul ghid de certificare.
Iar cu acestea fiind spuse a venit timpul sa pun prima bifa pe rezolutia de an si sa atasez noua sigla la blog.
Pentru aceia care se pregatesc, va urez mult succes!
-
A mai trecut un an iar PHP 6 nu va veni.
De 2 ani astept PHP 6, cred ca a devenit mai mult un blog traditional cu care sa inchei anul.
PHP 6 nu va mai veni pentru ca trunk-ul a fost abandonat si refacut dintr-unul de 5.3.
In alta ordine de idei PHP 5.3 castiga popularitate. Frameworkuri precum Zend Framework si Symfony pregatesc pentru anul 2011 cate o versiune in 2.0 care va avea nevoie de PHP 5.3+. Chiar si CodeIgniter, un framework traditional PHP 4, va necesita o data cu versiunea 2.0 minim PHP 5.1.6.
Mai mult, certificarea oficiala Zend pentru PHP este mai nou ZCE 5.3, iar aceasta devine destul de populara, chiar daca a fost lansata doar cu cateva luni in urma.
Dar un nou an se incheie si este timpul sa bifam realizariile din rezolutia de anul trecut si sa o scriem pe urmatoarea.
Anul trecut am terminat masterul, cu asta am incheiat mult prea multi ani de scoala decat imi doresc sa calculez. De fapt aceasta este prima iarna cand nu sunt intr-o forma de invatamant, poate de asta mi se pare ca am ceva mai mult timp liber :).
Am schimbat locul de munca, iar cu asta am fost fortat sa folosesc cateva lucruri care erau pe lista de TODO de ceva vreme:
- Linux
- Symfony Framework Linux era un subiect in jurul caruia ma invart inevitabi de destul de multi ani, fara sa-l aprofundez de loc. A fost mereu pe lista mea de “todo”, dar niciodata nu am avut atata rabdare ca sa intru in detalii cu el sau nu am avut continuitate atunci cand am facut-o. Cand am ajuns la noul loc de munca m-am trezit in fata unui calculator cu Ubuntu si un pic de panica m-a cuprins.
Dupa cateva luni am facut un nou pas, pentru prima data in viata mea am fost la un curs profesional. Cursul era organizat de Info Academy. Platit din buzunarul meu si usor suprapus cu programul de lucru. Dar am ajuns la concluzia ca trebuie sa-l fac. Probabil nu suna ca mare lucru, dar pentru mine care sunt in general autodidact a fost destul de ciudat. Acum ca s-a terminat pot spune ca a fost o foarte buna investitie si il recomand.
Undeva pe parcursul cursului mi-am dat seama ca e timpul sa mai fac cate un boot in linux si acasa. Urmatorul pas a fost reconfigurarea boot managerului sa booteze direct in linux. Acum, dupa ce folosesc aproape exclusiv linux, am ajuns la concluzia ca este suficient de user friendly incat sa fie o alternativa reala pentru Windows.
Symfony framework este alt subiect prafuit pe lista de “todo”. Desi am mai abordat CodeIgniter si Zend Framework, de Symfony nici macar nu m-am apropiat pana anul trecut. Se simte diferenta fundamentala de concept dintre ZF si Symfony, iar eu am simtit-o pe pielea mea. Acesta a fost alt motiv de panica pentru mine la noul loc de munca, pana la urma “all frameworks suck”.
Nu este un framework usor de invatat din pricina conceptelor, dar acum sunt de parere ca merita. Ce-mi place cel mai mult la acest framework este generarea de CRUD, care se face foarte usor si totusi este foarte puternica si flexibila. De asemenea flosirea fisierelor YML, care se pare ca au fost preluate de la Ruby on Rails, este o alternativa mult mai buna la fisierele ini care sunt suportate nativ in PHP.
Ca sa concluzionez, 2010 a fost un an bun, cu multe realizari, chiar daca nu am bifat totul pe rezolutia de anul trecut, cred ca am bifat destule.
Iar acum va urez un an 2011 mai bun si plin de realizari! La multi ani!
-
De cand a fost lansat PHP 5.3 anul trecut m-am intrebat daca Zend vor introduce si o certificare ZCE aferenta acestei versiuni.
Se pare ca o data cu abandonul versiunii PHP 6 cu ceva timp in urma directia a fost catre o certificare pentru PHP 5.3.
Perioada cred ca nu a fost intamplatoare avand in vedere ca se apropie Zend Con, cea mai mare conferinta PHP.
Ce este nou?
Diferentele de la PHP 5 la PHP 5.3 se gasesc in manual aici.
Cateva mai importante:
Materiale
Programa pentru examen se gaseste pe site-ul Zend.
Dupa ce la certificarea pentru Zend Framework am vazut ca exista un guide complet gratuit pentru membrii inregistrati, ma intrebam de ce nu exista asa ceva si pentru aceasta certificare. Se pare ca acum exista: Zend-PHP-5.3-Study-Guide-v1-3.pdf, in versiune beta! Si este gratuit!
Evident cel mai important material ramane manualul PHP, pentru ca ghidul se foloseste impreuna cu acesta.
Se pare ca nu mai exista mock tests, cum nu au existat nici pentru certificarea de Zend Framework.
Pret
Pretul se pare ca a mai crescut, nu mai este 160$ ci 190$! Pretul oricum ramane unul foarte mic avand in vedere ca un examen la Sun era 200$, iar acum 300$ la Oracle.
Persoanele care au deja o certificare PHP au un discaunt de 20% pana la finalul anului, deci daca esti deja certificat vei plati 152$.
Mult succes!
-
Factory method design pattern introdus de GoF (Gang of Four) pe care l-am abordat si eu intr-un blog anterior, are la baza ideea unei metode care genereaza obiecte. In general implementarea este destul de “slaba” pentru ca “factory”-ul este destul de hardcodat (la fel ca mine in blogul anterior).
PHP 5.3 ofera totusi posibilitatea unei implementari foarte interesante folosind “Late static bindings“.
Clasele pe baza carora se vor genera obiectele:
1// clasa abstracta de baza care urmeaza sa fie mostenita 2abstract class Drink { 3 4 // ingrediente 5 protected $ingredients; 6 7 // metoda publica care genereaza bautura 8 abstract public function MakeDrink(); 9} 10 11// o clasa derivata pentru ceai 12class Tea_Drink extends Drink { 13 14 // ingrediente pentru ceai 15 protected $ingredients = array('tea', 'sugar', 'mink', 'water'); 16 17 // generare ceai 18 public function MakeDrink() { 19 20 // fa ceai 21 } 22} 23 24// clasa derivata pentru Bloody Mary 25class BloodyMary_Drink extends Drink { 26 27 // ingrediente Bloody Mary 28 protected $ingredients = array('votka', 'salt', 'tomato juice'); 29 30 // generare Bloody Mary 31 public function MakeDrink() { 32 33 // fa BloodyMary 34 35 } 36}
Idea este de a avea o clasa abstracta care va fi extinsa intr-un mod cat mai simplu pentru a genera noi clase factory.
PHP 5
In PHP 5 clasa ar arata cam asa:
1// clasa Factory abstracta 2abstract class absFactory { 3 4 // numele clasei de baza 5 static protected $base_class = ''; 6 7 // metoda factory 8 public static function getInstance($type) { 9 10 // numele clasei rezultat 11 $class_name = $type . '_' . self::$base_class; 12 13 // se testeaza daca clasa exista 14 // aici se poate adauga si un autoloader eventual 15 if(!class_exists($class_name)) { 16 throw new Exception( 'Class ' . $class_name . ' not loaded!'); 17 } 18 19 // se verifica daca clasa mosteneste clasa de baza 20 if(!is_subclass_of($class_name, self::$base_class)) { 21 throw new Exception( 22 'Class ' . $class_name . ' is not a child of ' . self::$base_class 23 ); 24 } 25 26 // noul obiect 27 return new $class_name; 28 29 } 30 31}
Pentru ca metoda getInstance este statica si proprietatea este statica.
Daca incercam:
1class DrinkFactory extends absFactory { 2 3 static protected $base_class = 'Drink'; 4} 5 6try { 7 8 $obj = DrinkFactory::getInstance('Tea'); 9 10} catch (Exception $e) { 11 12 echo $e->getMessage(); 13}
Output-ul va fi:
1Class Tea_ not loaded!
Din pricina “self”, nu putem apela pur si simplu metoda getInstance() din clasa copil pentru ca valoarea lui $base_class va fi “” in loc de “Drink”, trebuie suprascrisa metoda getInstance(). Lucru prea “complicat”.
O versiune functionala in PHP 5 ar fi:
1class DrinkFactory extends absFactory { 2 3 public static function getInstance($type) { 4 5 self::$base_class = 'Drink'; 6 7 // metoda factory a clasei factory de baza 8 parent::getInstance($type); 9 10 } 11 12} 13 14try { 15 16 $obj = DrinkFactory::getInstance('Tea'); 17 18} catch (Exception $e) { 19 20 echo $e->getMessage(); 21}
Dar nu mi se pare tocmai “elegant”.
PHP 5.3
Aici avem “Late static bindings”, care in principiu este introducerea cuvantului “static”.
Clasa de baza factory arata cam asa:
1// clasa Factory abstracta 2abstract class absFactory { 3 4 // numele clasei de baza 5 static protected $base_class = ''; 6 7 // metoda factory 8 public static function getInstance($type) { 9 10 // numele clasei rezultat 11 $class_name = $type . '_' . static::$base_class; 12 13 // se testeaza daca clasa exista 14 // aici se poate adauga si un autoloader eventual 15 if(!class_exists($class_name)) { 16 throw new Exception( 'Class ' . $class_name . ' not loaded!'); 17 } 18 19 // se verifica daca clasa mosteneste clasa de baza 20 if(!is_subclass_of($class_name, static::$base_class)) { 21 throw new Exception( 22 'Class ' . $class_name . ' is not a child of ' . static::$base_class 23 ); 24 } 25 26 // noul obiect 27 return new $class_name; 28 29 } 30 31}
O schimbare atat de mica permite totusi o clasa factory mult mai “atragatoare”:
1class DrinkFactory extends absFactory { 2 3 static protected $base_class = 'Drink'; 4 5} 6 7try { 8 9 $obj = DrinkFactory::getInstance('Tea'); 10 11} catch (Exception $e) { 12 13 echo $e->getMessage(); 14}
Practic in aceasta varianta nu se inlocuieste decat proprietatea statica relevanta in acest context.