-
Aceasta este o retrospectiva a ultimului an.
In caz ca inca se mai intreba cineva, nu, PHP 6 nu a aparut si nici nu va aparea prea curand, probabil.
De ce este relevant? De cand am inceput acest blog am avut la final de an un post legat de PHP 6 si faptul ca acesta nu a fost lansat. In 2008 era o intrebare populara, dar nimeni nu mai crede asta acum, asa ca voi incheia acest subiect acum. Sa revenim la anul care s-a incheiat.
Aproape de jumatatea anului a fost lansata versiunea PHP 5.5, aceasta aducand in plus functionalitati cum ar fi: finally , generators si multe alte inbunatatiri.
Ca in 5.4, nu sunt functionalitati definitorii pentru limbaj. In aceasta noua versiune chiar sunt lucruri care pot fi inlocuite cu usurinta, dar daca sunt prezente, sunt bine venite.
Chiar daca PHP da dovada de multa dinamica in ultima vreme, cred ca in acest an cuvintele cheie au fost HTML5 si JavaScript.
HTML5 are parte de multe imbunatatiri, iar componente mai vechi incep sa creasca in popularitate. Firmele incep sa investeasca in jocuri care functioneaza in browser folosing WebGL. Chiar si jocuri mai vechi sunt portate catre platforma, folosind tehnologii cum ar fi asm.js.
Si, pentru ca am vorbit de jocuri, mi se pare foarte interesant cum doar acum 5-7 ani jocurile bazate pe JavaScript erau destul de simpliste, iar acum sunt comparabile cu cele de pe PC sau console.
Cred ca revolutia web, pe care multi o asteptau, incepe sa prinda avant. In sfarsit Web-ul este o platforma in adevaratul sens al cuvantului si JavaScript un limbaj cu adevarat apreciat.
Succesul se datoreaza tuturor partilor, nu mai este vorba doar de ECMA sau doar de producatorii de browsere, acum este o adevarat dinamica. Revolutia Web este in plina desfasurare!
Cand vine vorba de backend, lumina reflectoarelor a fost asupra Node.js. Acesta incepe sa devina un jucator important. Au aparut frameworkuri noi si nu mai este o platforma folosita predominant de hackeri dornici sa exploreze tehnologii noi, ci si de companii mari, cum ar fi PayPal, LinkedIn si Yahoo, oferind un vot de incredere pentru acesta. Cred ca Node.js incepe sa-si gaseasca locul si o nisa de piata, iar eu, un fan JavaScript, nu pot sa fiu decat incantat.
Un avantaj al Node.js este ca nu trebuie sa ai grija mai multor versiuni de JavaScript, asa cum este necesar in browser. Asta permite folosirea ultimelor facilitati ECMA in mod liber, un mediu in care poti dezvolta JavaScript fara dureri de cap.
Tehnologic vorbind, a fost un an foarte interesant pentru web development.
In final, va doresc tuturor un 2014 extraordinar de bun!
-
Cea mai noua versiune de PHP este aproape gata. In momentul cand scriu acest blog, PHP 5.5 este in RC 1.
Cum am mai spus si in blogul anterior, lista de noutati este disponibila la: http://www.php.net/manual/en/migration55.new-features.php
Al doilea feature ca popularitate este “finally”: http://www.php.net/manual/en/language.exceptions.php
Care-i treaba cu “finally“?
Pare un pic confuz, pare un bloc care se executa dupa ce se termina blocul de try catch. Dar ce este nou?
Sa zicem ca avem un bloc try/catch:
PHP 5.x < 5.5:
1// open resouce 2$resource = new Resouce(); 3try { 4 // do stuff with the resouce 5 $resouce->doStuff(); 6} catch (Exception $e) { 7 // log exception 8 syslog(LOG_ERR, $e->getMessage()); 9} 10// release resouce 11unset($resouce);
PHP 5.5
1// open resouce 2$resource = new Resouce(); 3try { 4 // do stuff with the resouce 5 $resouce->doStuff(); 6} catch (Exception $e) { 7 // log exception 8 syslog(LOG_ERR, $e->getMessage()); 9} finally { 10 // release resouce 11 unset($resouce); 12}
Pana aici nu exista nici un motiv pentru care este nevoie de un nou bloc. Am prins exceptia, am facut logging pe ea si am continuat.
Dar sa zicem ca este o resursa si vrem sa o eliberam, iar ulterior sa aruncam exceptia. O varianta ar fi sa eliberam resursa in catch.
Dar mai ramane cazul “fericit”, sa zicem ca trebuie sa o eliberam si atunci.
1// open resouce 2$resource = new Resouce(); 3try { 4 // do stuff with the resouce 5 $resouce->doStuff(); 6} catch (Exception $e) { 7 // release resouce 8 unset($resource); 9 // perpetuate exception 10 throw $e; 11}
Sa complicam si mai mult, sa zicem ca avem n tipuri de exceptii. Vor rezulta n conditii de catch, plus 1 pentru cazul fericit, iar in toate trebuie sa eliberam resursa. Nu foarte eficient…
O alta varianta este sa stocam exceptia intr-o variabila si, dupa ce am eliberat resursa, sa aruncam si exceptia, daca este cazul.
1// variable to store the exception 2$exception = false; 3 4// open resouce 5$resource = new Resouce(); 6try { 7 // do stuff with the resouce 8 $resouce->doStuff(); 9} catch (Exception $e) { 10 $exception = $e; 11} 12 13// release resouce 14unset($resource); 15 16if($exception) { 17 throw $exception; 18}
Acesta este unul din modurile in care se realizeaza in prezent. Functioneaza, dar nu evidentiaza faptul ca poate doar vrem sa eliberam resursa si sa ne continuam viata in liniste.
Varianta PHP 5.5
In manualul php.net:
In PHP 5.5 and later, a finally block may also be specified after the catch blocks. Code within the finally block will always be executed after the tryand catch blocks, regardless of whether an exception has been thrown, and before normal execution resumes.
De fiecare data cand blocul se executa, indiferent daca se executa cu succes sau nu, finally se va executa. Deci, pentru exemplul:
1try { 2 echo 'Do stuff' . PHP_EOL; 3 throw new Exception('testing'); 4} finally { 5 echo 'inside finally' . PHP_EOL; 6}
Outputul va fi:
1Do stuff 2inside finally 3 4Fatal error: Uncaught exception 'Exception' with message 'testing' in...
Daca vrem sa prindem si exceptia:
1try { 2 echo 'Do stuff' . PHP_EOL; 3 throw new Exception('testing'); 4} catch (Exception $e) { 5 echo 'do something with the exception' . PHP_EOL; 6} finally { 7 echo 'inside finally' . PHP_EOL; 8}
Outputul va fi:
1Do stuff 2do something with the exception 3inside finally
Si chiar daca luam cazul si mai particular, cand prindem exceptia, apoi o aruncam:
1try { 2 echo 'Do stuff' . PHP_EOL; 3 throw new Exception('testing'); 4} catch (Exception $e) { 5 echo 'do something with the exception' . PHP_EOL; 6 throw $e; 7} finally { 8 echo 'inside finally' . PHP_EOL; 9}
Pare ca acum am reusit sa prevenim executia blocului finally? Nu este tocmai asa…
1Do stuff 2do something with the exception 3inside finally 4 5Fatal error: Uncaught exception 'Exception' with message 'testing' in...
Cu alte cuvinte, blocul finally se executa de fiecare data, indiferent de rezultat.
-
O noua versiune de PHP este pe cale sa se lanseze. In momentul cand scriu acest blog, PHP 5.5 este in beta4.
Dornic de a vedea noutatile, am compilat noua versiune beta. Lista de noutati este disponibila la: http://www.php.net/manual/en/migration55.new-features.php
Cel mai important feature il reprezinta generatoarele (generators).
Generare de generators in PHP 5.5
Un generator este practic o functie care contine un apel catre “yield”.
Sa luam exemplul de pe php.net:
1<?php 2function xrange($start, $limit, $step = 1) { 3 for ($i = $start; $i <= $limit; $i += $step) { 4 yield $i; 5 } 6} 7 8echo 'Single digit odd numbers: '; 9 10/* Note that an array is never created or returned, 11 * which saves memory. */ 12foreach (xrange(1, 9, 2) as $number) { 13 echo "$number "; 14} 15?>
Practic, generatorul (xrange in acest caz), in loc sa intoarca un array, o sa genereze cate o valoare pentru a fi prelucrata.
Dar stai… oare asta nu era deja posibil pana la aceasta versiune?
Generatori inainte de PHP 5.5
Pana la versiunea de PHP 5.5 aveam deja iteratori:
1<?php 2 3class xrange implements Iterator 4{ 5 private $position = 0; 6 private $start; 7 private $limit; 8 private $step; 9 10 public function __construct($start, $limit, $step = 1) 11 { 12 $this->start = $start; 13 $this->limit = $limit; 14 $this->step = $step; 15 $this->position = 0; 16 } 17 18 function rewind() 19 { 20 $this->position = 0; 21 } 22 23 function current() 24 { 25 return $this->start + ($this->position * $this->step); 26 } 27 28 function key() 29 { 30 return $this->position; 31 } 32 33 function next() 34 { 35 ++$this->position; 36 } 37 38 function valid() 39 { 40 return $this->current() <= $this->limit; 41 } 42} 43 44echo 'Single digit odd numbers: '; 45 46/* Note that an array is never created or returned, 47 * which saves memory. */ 48foreach (new xrange(2, 9, 2) as $number) { 49 echo "$number "; 50} 51?>
In afara de faptul ca Iteratorul este un obiect cu mai multe proprietati, practic putem atinge acelasi rezultat.
Dar de ce era nevoie de generatori atunci? Simplu! In loc sa folosim ~40 linii de cod, putem folosi pur si simplu 5 ca sa atingem acelasi scop.
Un alt lucru interesant este ca:
1get_class(printer());
va intoarce Generator.
Deci, practic, un generator va intoarce inapoi un obiect de tip Generator, iar acest obiect extinde Iterator.
Diferenta majora, asa cum este si pe site-ul php.net, este ca generatorul nu poate fi resetat, merge intr-o singura directie.
Trimiterea de informatii catre generator
Da, generatorii functioneaza in doua sensuri, doar ca un anume generator este bun doar pentru un singur sens. Daca sintaxa de mai sus este pentru “producerea” de rezultate, sintaxa de mai jos este pentru “consumare” de date.
Sintaxa pentru un generator “consumator” este simpla:
1<?php 2function printer() { 3 $counter = 0; 4 while(true) { 5 $counter++; 6 $value = yield; 7 echo $value . $counter . PHP_EOL; 8 } 9 echo ‘Never executed...' . PHP_EOL; 10} 11 12$printer = printer(); 13$printer->send('Hello!'); 14echo 'Something is happening over here...' . PHP_EOL; 15$printer->send('Hello!'); 16?>
Outputul va fi:
1Hello!1 2Something is happening over here... 3Hello!2
Practic, valoarea din yield poate fi folosita ca orice alta valoare. Ce este interesant este while-ul. Pe php.net este urmatorul comentariu:
// Sends the given value to the
// generator as the result of
// the yield expression and
// resumes execution of the
// generator.Este nevoie de un loop, pentru ca generatorul se va opri dupa ce proceseaza valoarea si va continua doar atunci cand primeste o noua valoare. Daca scoatem while-ul, doar prima valoare va fi procesata, indiferent de cate ori vom apela send().
Un lucru interesant este ca ceea ce este dupa loop nu se va executa, in cazul meu linia:
1echo ‘Never executed...' . PHP_EOL;
Desi pare un loc potrivit sa eliberezi o resursa (ex. BD sau fisier), de fapt nu este, pentru ca acel cod nu se va executa.
Mi se pare util la logging. Din nou, nimic ce nu putea fi facut si pana acum, dar totusi permite o abordare mult mai usoara.
Am descoperit totusi un lucru care nu functioneaza:
1<?php 2function printer() { 3 while(true) { 4 echo yield . PHP_EOL; 5 } 6} 7 8$printer = printer(); 9$printer->send('Hello world!'); 10 11foreach($printer as $line) { 12 echo $line . PHP_EOF; 13}
Un pic haotic, nu? Eram curios ce se intampla:
Fatal error: Uncaught exception ‘Exception’ with message ‘Cannot rewind a generator that was already run’ in…Odata ce a fost folosit send() pe un iterator, nu mai poti sa iterezi prin el. Evident se poate genera unul nou, cu:
1printer();
Ce este si mai confuz este ca Generator este o clasa final, deci nu poate fi extinsa, iar daca incerci sa o instantiezi direct (desi chiar daca ar functiona ar fi inutil):
Catchable fatal error: The “Generator” class is reserved for internal use and cannot be manually instantiated in…Concluzia
Este un feature interesant, pentru ca simplifica mult lucrurile atunci cand vrei sa construiesti un iterator.
De asemenea, functionalitatea de send() mi se pare foarte interesanta, nu pentru ca face ceva nou, ci pentru ca il face mai usor.
Nu-mi place in schimb ca este aceeasi sintaxa pentru ambele variante de generatori si mai mult, ce este dupa while nu se mai executa.
Mi se pare usor confuza sintaxa, pentru ca nu este o diferentiere clara. Pe de alta parte, se pare ca asta exista deja in Python, deci pentru inspiratie se pot folosi exemplele din acest limbaj.