Flex pentru programatorii PHP

Am lucrat cu tehnologii web încă de la sfârşitul anilor ’90 şi prima tehnologie în ceea ce priveşte serverele cu care am interacţionat a fost PHP. Mai târziu, am utilizat serverul de aplicaţie ColdFusion şi Java, dar întotdeauna m-am considerat un dezvoltator PHP. Atunci când AJAX-ul a prins aripi, am început să lucrez cu framework-uri ca de exemplu Prototype şi script.aculo.us şi am început să-mi construiesc propriile framework-uri.

La sfârşitul anului 2006, am avut primele experienţe cu framework-ul Flex. A fost un fel de curs cu program de lucru intensiv deoarece într-un interval de timp de 4-6 săptămâni a trebuit să creez o aplicaţie demo pentru versiunea ulterioară a FDS (Flex Data Services denumite în prezent LiveCycle Data Services). Deşi atât Flex cât şi FDS erau relativ noi pentru mine, proiectul a decurs bine şi m-am bucurat de procesul de dezvoltare şi învăţare.

Oricât de plăcut ar fi fost era totuşi diferit.  Ceea ce vreau să spun este că în momentul dezvoltării aplicaţiilor web folosind ColdFusion sau Java nu am avut experienţe diferite comparativ cu utilizarea PHP; era mai mult vorba despre găsirea API-urilor potrivite pentru programarea aplicaţiilor şi adaptarea la caracteristicile speciale ale limbajului. Nici când am adăugat AJAX şi DHTML procesul nu a fost fundamental diferit. Este vorba tot de aceeaşi tehnică de programare pentru crearea majorităţii site-urilor web interactive cu ajutorul limbajului de pe server dar „AJAX-ifici” porţiuni din site.

În momentul în care am facut primul meu proiect web utilizând Flex, a fost într-adevăr o schimbare! Separarea distinctă dintre client şi server (ai business logic atat la nivel de server cât şi de client), clientul care este compilat şi nu interpretat, două limbaje, toate acestea necesitau o abordare conceptuală diferită de dezvoltarea web tradiţională.

Şi acesta este şi motivul care m-a determinat să scriu acest articol. Doresc să împărtăşesc cu voi unele dintre aspectele care sunt specifice pentru Flex în relaţie cu PHP. În acelaşi timp doresc să introduc Flex prin compararea acestuia cu PHP ori de câte ori această comparaţie este justificată. Prin urmare articolul este destinat:

  • Dezvoltatorilor PHP care doresc să înveţe despre Flex şi Action Script 3 mai mult decât ar putea furniza o definiţie simplă
  • Dezvoltatorilor PHP care au făcut deja o primă încercare de a coda o aplicaţie Flex şi doresc să aprofundeze subiectul

Ce nu este acest articol? Nu are intenţia de a vă converti sau de a vă convinge că Flex este mai bun decât X sau Y. Cred cu convingere că există tipuri diferite de proiecte cu cerinţe şi specificaţii diferite care nu pot fi satisfăcute cu un set de unelte universale în mod optim.

În acelaşi timp acest articol nu realizează o documentare exhaustivă a framework-ului Flex. Există zeci de cărţi în literatura de specialitate care acoperă aceste subiecte în cuprinsul a sute de pagini. Există sute de articole despre Flex. Intenţia mea este să vă asigur suficiente informaţii asupra celor mai importante subiecte şi, ori de câte ori abordarea este logică să asociez conceptele unor concepte similare din PHP. Pentru ca acest articol să fie util l-am structurat şi am încercat să nu intru în prea multe detalii. La sfârşitul acestui articol ofer o scurtă introducere în Adobe AIR şi câteva resurse suplimentare în eventualitatea în care doriţi informaţii adiţionale despre acest subiect.

În cele din urmă am ales să utilizez Flex 3 pentru majoritatea exemplelor furnizate. Sunt două motive pentru alegerea făcută. În primul rând în momentul scrierii acestui articol Flex 4 se afla încă în versiunea beta. În al doilea rând Flex 4 constituie, în principal, o dezvoltare a lui Flex 3. Prin urmare majoritatea aspectelor de care mă ocup în cuprinsul acestui articol pot fi aplicate şi pentru Flex 4 cu modificări minime, acolo unde este cazul. În unele situaţii voi atrage atenţia asupra acestor diferenţe.  În ceea ce priveşte PHP am ales să utilizez PHP 5.3 drept referinţă. Acestea fiind spuse să urmărim împreună cuprinsul şi apoi hai să aprofundăm!

  1. Ce este Flex?
    1. Flex: două limbaje, un singur framework care să le uneasca
    2. De ce ar trebui să vă intereseze Flex
    3. De la tehnologia thin client la terminalele smart/rich client
  2. Introducere în limbajul MXML
    1. Combinarea dintre limbajele de programare MXML şi ActionScript 3
    2. Stiluri CSS
    3. Modificarea codului MXML în timpul rulării
  3. Introducere în limbajul ActionScript 3
    1. Separarea declaraţiilor
    2. Tipuri de date, variabile, constante
    3. Funcţii şi funcţii anonime (closures)
    4. OOP: clase şi interfeţe
    5. Domeniul de existentă a variabilei (scope)
    6. Array-uri
    7. Namespaces
    8. Lucrul cu XML
    9. ActionScript dinamic
  4. Natura asincronă a Flex-ului
  5. Data binding, taguri metadata şi reflexie
  6. Unde sunt datele mele, aduceţi-le!
  7. Autentificarea utilizatorului în proiectele Flex şi PHP
  8. Lucrul cu proiectele Flex şi PHP
    1. Flex SDK
    2. Flex Builder / Flash Builder
    3. Depanarea aplicaţiilor Flex
  9. Ce este Adobe AIR?
  10. Ce urmează?
  11. Care este următorul pas?

Ce este Flex?

Cel mai simplu răspuns este: Flex reprezintă doar o altă modalitate de creare a aplicaţiilor Flash. O aplicaţie Flex este compilată într-un format de fişier SWF care este redat în browser-ul web prin intermediul Flash Player-ului. De ce este necesară o altă modalitate de creare a aplicaţiilor Flash? În mod tradiţional aplicaţiile Flash erau create prin utilizarea programului Flash Professional. Dacă aruncaţi o privire peste această unealtă veţi observa că este destinată în primul rând designerilor şi în al doilea rând programatorilor.  Există un canvas şi instrumente de desenat, timeline pentru animaţii, şi aşa mai departe.

În momentul în care dezvoltaţi aplicaţii si nu animaţii şi sunteţi interesaţi de productivitate iar unicitatea designului este pe planul doi, doriţi componente, doriţi să puteţi reutiliza codul şi nu în ultimul rând doriţi un IDE modern.

Prin urmare un răspuns revizuit ar putea fi: Flex este un framework open source care ajută dezvoltatorii să creeze rapid RIA (Rich Internet Applications) care rulează în Flash Player. Aplicaţiile Flex pot fi rulate in Flash Player 9 sau mai nou şi pot folosi limbajul ActionScript 3. Versiunea curentă este Flex 3 şi la începutul anului 2010 va fi publicată şi versiunea următoare, Flex 4.

flex_php_0[top]

Flex: două limbaje, un singur framework care să le uneasca

În produsul Flex vom găsi următoarele:

  • Două limbaje de programare: MXML şi ActionScript 3. Flex oferă două limbaje de programare pentru a crea o aplicaţie Flex. În următoarele capitole voi aprofunda fiecare limbaj în parte.
  • O bibliotecă bogată de componente
  • Compilatoare şi debugger
  • Unelte pentru linia de comandă (Command-line) pentru compilarea şi depanarea unei aplicaţii Flex

Din moment ce Flex este un framework open source, vă încurajez să accesaţi pagina principală a proiectului la http://opensource.adobe.com/flex şi să descărcaţi SDK-ul. Puteţi vizualiza codul sursă al tuturor componentelor, puteţi verifica baza de date deschisă Bugs & Features (http://bugs.adobe.com/flex),  şi puteţi vedea paginile wiki pentru specificaţii.

O parte din creşterea productivităţii asigurată prin Flex este datorată bibliotecii extinse de componente. Sunt acolo toate componentele UI pe care vi le-aţi putea imagina (text inputs, panels, ferestre, cursoare, liste de selecţie, accordions, tab sets, …). Există containere pentru a crea layout-uri şi elemente pentru creare forme. Mai jos puteţi vedea o captură de ecran a componentelor UI disponibile în Flex 3 (faceţi clic pentru mărire).

flex_php_1

Şi dacă toate acestea nu sunt suficiente deoarece aveţi posibilitatea să accesaţi codul sursă puteţi extinde aceste instrumente pentru a construi propriile voastre componente sau puteţi crea componente noi de la zero.

[top]

De ce ar trebui să vă intereseze Flex

Înainte de a aprofunda definirea framework-ului Flex haideţi să ne oprim şi să reluăm motivele pentru care ar trebui să vă intereseze Flex.

Aplicaţiile web tradiţionale realizate cu HTML sunt de tipul cerere –răspuns. Browser-ul iniţiază o cerere şi server-ul trimite o pagină înapoi şi acest ciclu se repetă. HTML şi CSS reprezintă o alegere excelentă pentru prezentarea informaţiilor, dar este discutabil dacă acestea reprezintă unele dintre cele mai bune tehnologii existente pentru realizarea de aplicaţii web (deci aplicaţii care oferă mai mult decât citirea pasivă a informaţiei).

Cu toate acestea, pe măsură ce anii au trecut, această arhitectură a depăşit simpla prezentare statică pentru a deveni o platformă de aplicaţii. Odată cu tehnologiile axate pe partea de scripting am reuşit să creăm pagini dinamice şi să adaptăm răspunsul server-ului pentru a satisface o cerere specifică. Mai mult, adăugarea DHTML-ului şi AJAX-ului au imprimat o dinamică nouă paginilor web: utilizatorul poate să interacţioneze cu pagina încărcată şi să interacţioneze cu conţinutul  astfel încât să nu fie nevoie ca pagina să fie reîncărcată la fiecare acţiune a utilizatorului.

Pe măsură ce tehnologiile au evoluat au apărut aplicaţii mai complexe. Unele aplicaţii web au început să reproducă multe funcţionalităţi ale aplicaţiilor pentru desktop  şi în acelaşi timp să păstreze utilitatea unei aplicaţii web (să fie disponibile oriunde este disponibil un browser şi o conexiune la Internet). Astfel au rezultat versiunile online ale editoarelor de tabele (sau programe „spreadsheet”) şi editoarelor de texte spre exemplu.

Cu toate acestea, din perspectiva posibilităţii de utilizare, aplicaţiile online erau mai puţin prietenoase decât aplicaţiile pentru desktop. În acelaşi timp pentru a crea aceste aplicaţii web complexe sunt necesare o multitudine de cunoştinţe şi competenţe privind multe tehnologii (JavaScript, DHTML, CSS, bibliotecile AJAX, tehnologiile server-side) şi trebuie să fi căpătat deja experienţă în ceea ce priveşte diferenţele dintre browsere şi modalitatea în care acestea au implementat standardele HTML/CSS/JS.

Astfel, în anul 2002, Macromedia a inventat termenul RIA – Rich Internet Applications pentru a descrie un nou val de aplicaţii care combină beneficiile aplicaţiilor web cu avantajele aplicaţiilor pentru desktop. Tehnologia care a făcut posibil acest lucru a fost Flash-ul.

Dacă se doreşte crearea unei aplicaţii (şi nu doar un site sau o pagină web), acest lucru este posibil utilizând Flex. Unele lucruri pur şi simplu nu sunt posibile cu HTML/JavaScript, altele ar fi foarte greu de implementat în mod corespunzător pentru toate browser-ele. Pe de altă parte Flash Player oferă unul dintre motoarele grafice cele mai bune; este instalat pe 98% dintre computerele conectate la Internet şi tratează sunetul şi videoul ca first class citizens. Flash Player are suport pentru microfoane şi webcam, suport pentru (dynamic) streaming şi transferul datelor, suport excelent pentru imprimare şi lista poate continua.

Uitaţi-vă la aceste trei aplicaţii pentru a vă forma o idee despre ce aţi putea realiza utilizând platforma Flex:

  • SumoPaint, o aplicaţie gratuită pentru prelucrarea şi editarea imaginilor
  • Mindomo, o aplicaţie pentru a lua note folosind tehnica mind-mapping
  • Times Reader o aplicaţie care facilitează accesul la conţinutul ediţiei tipărite a ziarului New York Times

În timp alte tehnologii au pătruns în spaţiul RIA. În afară de progresele AJAX care a făcut posibile aplicaţii precum Gmail sau Google Spreadsheets, în prezent suntem martorii apariţiei tehnologiei Silverlight de la Microsoft şi JavaFX de la Sun.

[top]

De la tehnologia thin client la terminalele smart/rich client

Să revenim la browsere şi la modul în care aplicaţiile web sunt transmise. Atunci când browser-ul realizează o cerere, server-ul utilizează o combinaţie de conţinut static (codul HTML/CSS/JavaScript) şi scripturi (PHP de exemplu; aceste scripturi pot interoga o bază de date sau pot apela alte scripturi, dar în cele din urmă acestea redau HTML/CSS/JS) pentru a pregăti o pagină. Această pagină este trimisă către browser care o randează pe ecran. Un element cheie aici este faptul că această pagină (sau răspuns) are de obicei limbajul de markup (HTML) şi datele cuprinse în interiorul aceluiaşi mesaj.

În momentul în care o nouă stare a aplicaţiei urmează să fie afişată, browser-ul face o nouă cerere şi server-ul pregăteşte pagina. Clientul „doar” afişează noua pagină.

Aplicaţiile Flex acţionează în mod diferit. Server-ul transmite aplicaţia Flex în versiunea compilată (formatul de fişier SWF) care rulează în interiorul browser-ului utilizând Flash Player. De obicei, acest format de fişier SWF reţine doar partea de business logic al aplicaţiei pe partea clientului. Dacă sunt necesare date (dintr-o bază de date de exemplu) aplicaţia Flex realizează o cerere pentru datele respective. Server-ul transmite doar datele (acestea pot fi în format XML, JSON, AMF3, sau un format propriu) şi clientul ştie cum să reprezinte aceste date în mod vizual. Este vorba aici despre o arhitectură de aplicaţii orientată către servicii (SOA): aplicaţia Flex reprezintă clientul – un client care poate consuma servicii de la server. Aplicaţia poate modifica starea fără să reincarce pagina sau fără să reîncarce SWF-ul în browser. Aplicaţia este un client care realizează mai mult decât „doar” să afişeze datele venite de la server. Astfel, utilizând Flex şi Flash Player este posibil să creăm aproape orice aplicaţie care are sens pe web de la jocuri la aplicaţii, widget-uri care sunt integrate în cadrul aplicaţiilor web „clasice” şi altele.

Dar gata cu teoria, să analizăm nişte cod!

[top]

Introducere în limbajul MXML

MXML este un limbaj declarativ bazat pe XML (Extensible Markup Language). În cadrul unei aplicaţii Flex utilizaţi MXML pentru a stoca şi specifica rapid structura/înfăţişarea aplicaţiei. În Flex, orice aplicaţie pe care o puteţi construi utilizând limbajul MXML poate fi realizată de asemenea şi cu ActionScript 3. Totuşi, raţionamentul invers nu este adevărat!

Dacă puteţi folosi ActionScript 3 pentru a realiza aceleaşi construcţii şi gestionări de interfeţe pe care le puteţi realiza cu MXML, de ce mai există atunci MXML? De obicei este mult mai uşor să urmărim sau să înţelegem o interfaţă cu utilizatorul descrisă prin utilizarea unui limbaj XML decât una imperativă. Şi acest lucru se traduce prin mai puţine linii de cod care trebuie scrise pentru a defini o interfaţă. De asemenea, este mult mai facil să construim unelte grafice pentru limbajele declarative decât pentru limbajele imperative. Mai jos puteti vedea un ”Hello world!” creat utilizând limbajul MXML:

   1: <Label text="Hello World!" fontSize="14" color="red" x="100" y="50"/>

În acest cod am utilizat o componentă Flex care reprezintă o etichetă pentru a afişa un anumit text pe ecran. Am stabilit atributul textului pe care doresc să-l afişez. Mai mult am vrut să personalizez (puţin) înfăţişarea şi poziţia etichetei pe ecran. Pentru aceasta utilizez atributele care setează dimensiunea font-urilor, culoarea, x şi y. Cred că sunteţi de acord că este destul de simplu de înţeles şi de urmărit.

Acum luaţi în considerare acelaşi exemplu realizat utilizând ActionScript 3:

   1: var myLabel = new Label();
   2: myLabel.text = "Hello World!";
   3: myLabel.setStyle("fontSize", "14");
   4: myLabel.setStyle("color", "red");
   5: myLabel.x = 100;
   6: myLabel.y = 50;
   7: addChild(myLabel);

Am, prin urmare, şapte linii de cod pentru a realiza ceea ce am construit în MXML doar cu un singur tag şi nişte atribute! Acum imaginaţi-vă că într-o aplicaţie reală aveţi o multitudine de controale grupate în containere diferite. Este mult mai uşor să păstraţi codul scris prin utilizarea limbajului MXML decât codul scris sub forma a sute de linii în ActionScript 3.

Deşi puteţi utiliza MXML pentru a descrie aplicaţia nu puteţi utiliza MXML pentru a pune în aplicare logica aplicaţiei. Pentru aceasta aveţi nevoie de ActionScript 3.

Aplicaţiile Flex rulează în Flash Player iar Flash Player înţelege doar ActionScript 2 şi ActionScript 3. Acest lucru înseamnă că orice cod MXML pe care îl scrieţi în aplicaţie trebuie transformat de compilatorul MXML într-un cod ActionScript 3. Codul este transformat de compilatorul ActionScript într-un limbaj intermediar portabil bytecode (un fişier SWF) ale cărui instrucţiuni pot fi înţelese de Flash Player.

Astfel, în spatele fiecărei componente MXML există o clasă implementată ActionScript 3 (de fapt există o excepţie la această regulă pentru ca sunt câteva tag-uri MXML care nu au o clasă ActionScript corespondentă, ca de exemplu Script şi Model). De exemplu, mai jos este redat un fragment din clasa Label:

   1: public class Label extends UIComponent
   2:                    implements IDataRenderer, IDropInListItemRenderer,
   3:                    IListItemRenderer, IFontContextComponent
   4:
   5: {
   6:     /**
   7:      *  Constructor.
   8:      */
   9:     public function Label()
  10:     {
  11:         super();
  12:
  13:         // this is so the UITextField we contain can be read by a screen-reader
  14:         tabChildren = true;
  15:     }
  16:
  17:     /**
  18:      *  @private
  19:      *  Flag that will block default data/listData behavior.
  20:      */
  21:     private var textSet:Boolean;
  22:
  23: ...
  24: }

În orice aplicaţie Flex aveţi cel puţin un fişier MXML care reprezintă aplicaţia principală. De exemplu, acesta este codul complet pentru exemplul “Hello World!”:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
   3:         <mx:Label text="Hello World!" fontSize="14" color="red" x="100" y="50"/>
   4: </mx:Application>

Nodul rădăcină trebuie să fie întotdeauna Application, şi aici este zona unde sunt definite namespaces-urile. În acest caz avem doar un singur namespace pentru limbajul MXML şi pentru componentele Flex: mx. (Codul anterior este în Flex 3, în Flex 4 există diferenţe minore şi anume există mai multe namespaces declarate).

Dacă veţi scrie propriile voastre componente personalizate trebuie să adăugaţi un namespace pentru ele. Aici, de exemplu, declar un al doilea namespace pentru a face referire la toate componentele pe care le-am creat (în acest exemplu utilizez o componentă label personalizată denumită MyCustomLabel; puteti vedea declaraţia namespace-ului local în nodul Application):

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*">
   3:     <mx:Label text="Hello"/>
   4:     <local:MyCustomLabel text="world!"/>
   5: </mx:Application>

În această etapă v-aţi putea întreba cum trataţi paginile diferite pentru o aplicaţie dezvoltată în Flex. Pentru un site web HTML, stări diferite sunt implementate, de obicei, în pagini diferite. O aplicaţie  Flex este destul de asemănătoare cu o aplicaţie pentru desktop. Aceasta înseamnă că puteţi utiliza un singur fişier MXML şi puteţi afişa în cadrul acestei pagini diferitele stări ale aplicaţiei. Flex asigură o multitudine de modalităţi de realizare a acestui lucru, de la componentele Flex precum Accordions, Tabsets navigators, Card layout la modulele Flex.

Aţi remarcat faptul că codul MXML poate fi utilizat pentru a defini înfăţişarea unei aplicaţii. Dar îl puteţi utiliza, de asemenea, pentru a crea componente personalizate prin extinderea componentelor Flex existente. Să luăm un exemplu. Să presupunem că aveţi în cadrul aplicaţiei voastre o mulţime de forme care prezintă două butoane: Save şi Cancel. Examinaţi codul pentru această componentă personalizată MXML (codul este creat în interiorul unui fişier denumit FormButtons.mxml; toate fişierele MXML trebuie să aibă extensia mxml):

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150">
   3:     <mx:Button id="saveButton" label="Save"/>
   4:     <mx:Button id="cancelButton" label="Cancel"/>
   5: </mx:HBox>

Atunci când creaţi o componentă personalizată puteţi selecta componenta pe care doriţi să o extindeţi (nu vi se permite să extindeţi Application). Am ales să extind HBox (Horizontal Box), un container care afişează toţi copiii pe aceeaşi linie. În interiorul containerului am adăugat două butoane, unul pentru Save şi celălalt pentru Cancel. Am setat de asemenea atributul id pentru fiecare în parte. Utilizaţi valoarea id ca modalitate de a face referire la obiect în alte zone ale codului. Acest lucru este similar cu declararea unei variabile în codul ActionScript.

Să vedem, în cele ce urmează, cum puteţi utiliza această componentă personalizată în cadrul unei aplicaţii Flex:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" layout="horizontal">
   3:     <mx:TextInput width="150"/>
   4:     <local:FormButtons/>
   5: </mx:Application>

Mai jos puteţi vedea cum arată aplicaţia:

flex_php_2

V-aţi putea gândi că în limbajul MXML puteţi utiliza doar componente Flex vizuale (şi anume componente care sunt afişate pe ecran). De fapt, acest lucru nu este adevărat. Puteţi avea componente MXML care reprezintă date (obiecte care sunt utilizate pentru a memora date) sau componente care manipulează date (componente care pot aduce/transmite date de la/către un server). Mai jos puteţi examina un exemplu de componentă-obiect generică care are o proprietate denumită  name:

   1: <mx:Object id="myObj" name="Mihai Corlan"/>

Aşa cum am afirmat mai sus, toate (sau aproape toate) componentele Flex care vin cu Flex au o clasă  ActionScript care implementeaza partea vizuală (dacă există) şi logica componentei. Atunci când alegeţi să creaţi o componentă personalizată (indiferent dacă este o componentă vizuală sau nu) utilizând ActionScript în loc de MXML, trebuie să nu uitaţi că există totuşi o restricţie: constructorul clasei trebuie să poată fi apelat fără argumente (şi dacă există argumente acestea trebuie să aiba valori default).

[top]

Combinaţia dintre limbajele de programare MXML şi ActionScript 3

Revenind la componenta personalizată FormButtons (aceea cu două butoane Save si Cancel), este posibil să fi remarcat o problemă: Ce se întâmplă dacă doriţi să utilizaţi această componentă într-o zonă în care etichetele Save şi Cancel nu au nicio logică? Ar trebui să creaţi altă componentă personalizată prevăzută cu etichetele corespunzătoare (să zicem Show şi Hide)? Bineînţeles că şi aceasta este o posibilitate dar nu este nici scalabilă nici elegantă! Ceea ce vă trebuie cu adevărat este o componentă cu caracteristici mai generale şi o modalitate de a modifica componenta utilizând codul. Din acest motiv, mai devreme sau mai târziu tot va trebui să adaugaţi cod ActionScript la codul MXML.

În următorul exemplu am adăugat codul ActionScript în interiorul codului MXML al componentei pentru a defini două variabile care memorează etichetele utilizate de butoane. Remarcaţi faptul că utilizez un nou tag, Script, şi în interiorul acestuia  CDATA. Aceasta se datorează faptului că în interiorul documentelor XML caractere precum >,<, & sunt ilegale dacă nu sunt escapate. De asemenea nu mă voi concentra prea mult acum asupra codului ActionScript dar voi relua subiectul mai detaliat în capitolele următoare.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150">
   3:     <mx:Script>
   4:         <![CDATA[
   5:             public var label1:String = "Save";
   6:             public var label2:String = "Delete";
   7:         ]]>
   8:     </mx:Script>
   9:     <mx:Button id="saveButton" label="{label1}"/>
  10:     <mx:Button id="cancelButton" label="{label2}"/>
  11: </mx:HBox>

Variabilele pe care le-am definit pot fi setate din aplicaţia Flex care utilizează această componentă. Prin urmare haideţi să vedem cum arată codul revizuit al aplicaţiei Flex atunci când se utilizează noua componentă personalizată:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" layout="horizontal">
   3:     <mx:TextInput width="150"/>
   4:     <local:FormButtons label1="Show" label2="Hide"/>
   5: </mx:Application>

Observaţi că există două atribute pe tagul FormButtons: label1 şi label2. Astfel veţi putea configura textul pe care doriţi să-l afişaţi pe butoane. Şi acesta este mecanismul pe care îl utilizaţi pentru a adăuga un răspuns specific unei componente MXML (utilizând codul ActionScript). În cadrul unei aplicaţii reale  este posibil să doriţi să asociaţi un răspuns specific fiecărui buton, astfel încât să se întâmple ceva atunci când butonul este apăsat. Utilizaţi codul ActionScript pentru a scrie funcţiile care vor fi declanşate prin apăsarea butoanelor.

Mai există şi o altă metodă pentru adăugarea codului ActionScript la MXML. Puteţi crea un fişier ActionScript (în acest exemplu numele fişierului este buttons.as) pe care să-l includeţi în fişierul MXML. Veţi realiza acest lucru prin adăugarea unui tab Script  cu un atribut source care indică fişierul ActionScript. Mai jos este redat codul pentru această abordare:

   1: // ActionScript file called buttons.as
   2: public var label1:String = "Save";
   3: public var label2:String = "Delete";
   
   
   1: <?xml version="1.0" encoding="utf-8"?>
   2: <!-- MXML component file called FormButtons.mxml a-->
   3: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150">
   4:     <mx:Script source="buttons.as"/>
   5:     <mx:Button id="saveButton" label="{label1}"/>
   6:     <mx:Button id="cancelButton" label="{label2}"/>
   7: </mx:HBox>

Haideţi să revenim puţin şi să înţelegem ce se întâmplă atunci când compilatorul MXML analizează fişierul FormButtons.mxml. Ştiţi deja că toate fişierele MXML vor fi transformate în cod ActionScript. Dar ce se întâmplă cu codul ActionScript existent pe care l-am adăugat (cele două variabile)? Compilatorul MXML translatează fiecare fişier MXML într-o clasă ActionScript. În acest caz va crea o clasă numită FormButtons (deoarece aceasta este denumirea fişierului şi este utilizată pentru numele clasei) care extinde componenta HBox (deoarece am ales HBox drept nodul rădăcină al componentei). Şi tot codul ActionScript din interiorul unei clase devine parte a clasei respective: variabilele (precum acelea din exemplul nostru) devin variabile/membri ai instanţei iar funcţiile devin metode ale instanţei.

[top]

Stiluri CSS

În acest moment v-aţi putea întreba dacă puteţi modifica înfăţişarea şi comportamentul componentelor vizuale Flex. Există ceva asemănător cu CSS pentru HTML? Răspunsul este pozitiv, Flex este o platformă care suportă CSS. În Flex 4 permisiunea pentru încărcarea stilurilor din fişiere .css este extinsă pentru a integra definirea stilurilor bazate nu numai pe nume de clase dar şi pe id-uri pentru a permite pseudo-selectori (de exemplu pentru un buton putem avea „down selector”, „over selector” şi aşa mai departe) şi multe altele.

Ca şi în HTML, stilurile pot fi definite inline (în interiorul codului MXML) sau într-un fişier separat. Să revenim la componenta personalizată, FormButtons şi să configurăm câteva stiluri. Dacă alegeţi să definiţi stilurile într-un fişier separat utilizaţi un tag Style şi configuraţi calea către fişierul CSS din cadrul atributului source. Mai jos este un exemplu cu CSS definit inline.

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <!-- MXML component file called FormButtons.mxml a-->
   3: <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="150">
   4:     <mx:Style>
   5:         .Button1 {
   6:             font-size: 14;
   7:             color: #990000;
   8:         }
   9:     </mx:Style>
  10:     <mx:Script source="buttons.as"/>
  11:     <mx:Button id="saveButton" styleName="Button1" label="{label1}"/>
  12:     <mx:Button id="cancelButton" label="{label2}"/>
  13: </mx:HBox>

Am creat o clasă CSS denumită Button1 care defineşte culoarea pentru etichetă şi dimensiunea fontului. Apoi am setat stilul la primul buton utilizand atributul styleName al primului buton. Aplicaţia arată acum conform imaginii de mai jos:

flex_php_3

Stilurile CSS pot fi schimbate pe parcursul timpului de rulare (după ce aplicaţia Flex este încărcată în browser) iar înfăţişarea aplicaţiei se va modifica imediat.În Flex 4, Adobe a adăugat un nou limbaj denumit MXML pentru interfeţe grafice care adaugă primitive grafice, efecte, măşti şi transformări 2D. Utilizând aceste noi taguri puteţi crea o clasă skin in MXML pentru a defini înfăţişarea unei componente Flex. În cele ce urmează puteţi observa o listă implementată în Flex 4. Imaginea din partea stângă arată lista în starea sa iniţială iar imaginea din dreapta arată starea „hover”. Puteţi vizualiza aplicaţia live aici.

flex_php_4 flex_php_5

În timp ce parcurgeţi documentaţia pentru a vă familiariza cu înfăţişarea aplicaţiilor Flex puteţi întâlni termenul de “skinning”. Puteţi realiza graphical skinning sau programmatic skinning pentru a modifica înfăţişarea. Un articol bun pe această temă puteţi citi  aici.

[top]

Modificarea codului MXML în timpul rulării

Uneori doriţi să modificaţi componentele UI în timpul rulării. Este posibil să intenţionaţi, în funcţie de anumite date pe care le recuperaţi de pe server, să contruiţi o formă la runtime. Din nou puteţi utiliza codul ActionScript pentru a realiza acest lucru. Orice componentă Flex care poate fi modificată vizual deţine metode pentru a adăuga  un nou element-copil (child) pentru a-l elimina, pentru a accesa toate obiectele-copii şi aşa mai departe. Dacă vreţi, puteţi compara această operaţie cu modul în care modificaţi DOM-ul în HTML utilizând JavaScript. Cu toate acestea, există o diferenţă: cu JavaScript puteţi injecta codul HTML pe care îl puteţi recupera în mod dinamic de pe un server (prin intermediul unui apel AJAX). În Flex acest lucru nu este posibil şi funcţia eval() nu există în Flex. Cu toate acestea există o modalitate prin care puteţi încărca alte aplicaţii sau module Flex după ce este încărcată aplicaţia principală.

Atunci când cunoaşteţi toate stările diferite posibile pentru o componentă puteţi utiliza MXML States pentru a defini stările diferite pentru aceeaşi componentă sau aplicaţie. States a suferit îmbunătăţiri majore în Flex 4 astfel încât utilizarea lor este mai uşoară. În Flex 4 stările funcţionează după cum urmează:

  1. Definiţi un număr de stări şi specificaţi starea standard
  2. Puteţi apoi specifica în care stări trebuie să apară o anumită componentă
  3. Puteţi specifica valori separate pentru orice atribut pentru fiecare stare acolo unde apare

Să presupunem că doriţi să creaţi o componentă care să aibă legătură cu funcţionalităţile de autentificare ale unei aplicaţii. Doriţi să utilizaţi această componentă pentru afişarea formei de conectare şi atunci când conectarea se realizează cu succes doriţi să afişaţi butonul de deconectare şi numele utilizatorului.

În cele ce urmează vă prezint cum puteţi crea această componentă de Login/Logout utilizând Flex 4:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo">
   3:     <s:states>
   4:         <s:State name="notlogged"/>
   5:         <s:State name="logged"/>
   6:     </s:states>
   7:
   8:     <s:TextInput includeIn="notlogged" text="user name"/>
   9:     <s:TextInput includeIn="notlogged" text="password"/>
  10:     <s:Button includeIn="notlogged" label="Login" click="{currentState='logged'}"/>
  11:
  12:     <mx:Label includeIn="logged" text="Current user: Mihai Corlan"/>
  13:     <s:Button includeIn="logged" label="Logout" click="{currentState='notlogged'}"/>
  14:     <s:layout>
  15:         <s:HorizontalLayout/>
  16:     </s:layout>
  17: </s:Group>

Codul ar trebui să fie uşor de urmărit. Ca şi container top utilizez o componentă Group care are layout-ul configurat pe HorizontalLayout (acest lucru are acelaşi efect ca şi componenta HBox utilizată în exemplul cu Flex 3 de mai sus). Am definit la începutul paginii stările disponibile pentru această componentă (notlogged si logged). Urmează acum butoanele, input-urile de text şi eticheta. Observaţi atributele includeIn care specifică în ce stare apare componenta. Există de asemenea şi atributul excludeFrom. Dacă doriţi ca un buton să acopere toate stările aplicaţiei atunci nu trebuie să specificaţi nimic pentru aceste două atribute. La final observaţi că am atribuit o expresie pentru atributele click ale celor două butoane. De exemplu atributul click=”{currentState=’logged’}” transmite aplicaţiei Flex că atunci când se dă clic pe buton se va modifica starea componentei într-una denumită logged.

Am inclus din ce în ce mai multe coduri ActionScript în aceste exemple deşi vă vorbesc încă despre limbajul MXML. Aceasta înseamnă că este timpul să analizăm cel de-al doilea limbaj din Flex, şi anume ActionScript 3.

[top]

Introducere în limbajul ActionScript 3

ActionScript 3 este un limbaj de scripting dinamic, orientat obiect şi al cărui tip de date este (aproape) type-safe. ActionScript 3 se bazează pe specificaţiile ECMAScript 3 (ECMA-262). De asemenea, unele dintre caracteristicile acestuia sunt în linie cu propunerea iniţială  ECMAScript 4. Am descoperit că cea mai simplă modalitate de a explica ActionScript 3 unei persoane care nu are nicio idee despre acest limbaj este următoarea: ActionScript arată ca o combinaţie de JavaScript şi Java şi în plus are propria personalitate puternică. De fapt, JavaScript este un alt limbaj bazat pe specificaţiile ECMAScript; prin urmare este firesc să aibă aspecte comune cu ActionScript.

Aşa cum am menţionat anterior Flash Player poate să lucreze cu două limbaje: ActionScript 2 şi ActionScript 3. Acesta utilizează două maşini virtuale diferite pentru a rula byte-codeul rezultat din  aceste două limbaje (ActionScript 3 şi maşina virtuală AVM2 au apărut Flash Player 9). ActionScript 3 se compune din limbajul principal (cuvinte cheie, tipuri de date şi aşa mai departe) şi Flash Player API (API-uri care oferă dezvoltatorilor acces la toate caracteristicile Flash Player display list, 3D API, metodele de desenare API, Animaţii, şi aşa mai departe). În cadrul acestui articol îmi voi îndrepta atenţia către limbaj si nu către API-urile.

Aici găsiţi un articol introductiv bun despre ActionScript 3.De aici înainte voi utiliza abrevierea “AS3” pentru a mă referi la “ActionScript 3”.

[top]

Separarea declaraţiilor

În PHP utilizaţi punct şi virgulă (;) pentru a despărţi sau pentru a termina o declaraţie. În AS3 puteţi utiliza punct şi virgulă (;) sau pur şi simplu eol (end of line). Trebuie să vă spun că nu este o plăcere să citesti cod scris fără punct şi virgulă. Prin urmare vă sugerez să utilizaţi acceaşi metodă pe care o abordaţi şi în PHP.

[top]

Tipuri de date, variabile, constante

În PHP există următoarele tipuri de date: Booleans, numere întregi, numere reale exprimate în virgulă mobilă, Strings, Array, Obiecte, Resurse şi NULL.

În AS3 avem:

  • Tipuri de date simple: Boolean, int, uint, Number (aceleaşi ca numerele reale din PHP exprimate în virgula mobilă), Strings, Null (conţine doar o singură valoare: null), void (conţine doar o singură valoare: undefined)
  • Tipuri de date complexe: Object, Array, Vector (începând cu Flash Player 10), Dictionary, Bitmap, ByteArray, Date, XML, XMLList, Function, Error, RegExp

În AS3, o variabilă este doar un identificator sau o referinţă asociată cu valoarea reală. Valorile legale în AS3 sunt Object (int sau uint sunt obiecte, acelaşi lucu este valabil şi pentru Number sau Date), null, şi undefined. null şi undefined înseamnă absenţa datelor; cu toate acestea există o diferenţă între ele. Atunci când declaraţi o variabilă şi nu o iniţializaţi aceasta va avea valoarea null dacă tipul variabilei nu este Boolean, int, uint, sau Number. Dacă variabila nu are tipul declarat şi nu este iniţializată va avea valoarea undefined. În acelaşi timp atunci când aveţi un obiect dinamic şi intenţionaţi să verificaţi dacă o anumită metodă sau proprietate este definită puteţi să controlaţi prin comparaţie cu undefined.

În PHP declaraţi o variabilă după cum urmează:

   1: $anInteger = 12;
   2: $isTrue = true;
   3: $aString = "my string";
   4: //or
   5: $aString = 'my string';

În AS3 utilizaţi cuvântul cheie var atunci când declaraţi o variabilă:

   1: var anInteger:int = 12;
   2: var isTrue:Boolean = true;
   3: var aString:String = "my string";
   4: //In AS3 you can not use simple quotes for declaring a String

Observaţi că după numele variabilei există o adnotare; de exemplu, myVarName:Boolean (tipul este declarat utilizând simbolul “:” urmat de tipul respectiv). AS3 vă permite să lucraţi fie cu declarea tipului de data a variabilei fie fără acesta (dacă modul strict pentru compilator este configurat atunci trebuie să includeţi tipul de dată).

Dacă vă gândiţi la comparaţia cu PHP unde nu trebuie să declaraţi tipul variabilei acest lucru vi se poate părea ciudat şi este posibil să rămâneţi credincios modalităţii „untyped” în care variabilele nu au un tip specificat. Oricât de tentant ar fi acest lucru vă încurajez să utilizaţi declaraţiile de tip. În primul rând atunci când folosiţi un IDE pentru scrierea codului vă va permite să găsiţi erori la compilare. De exemplu să ne gândim la o funcţie care are un singur argument de tip String. Dacă încercaţi să apelaţi această funcţie si pasati un Object drept argument, IDE-ul vă va alerta despre eroarea respectivă.

Fără tipul de dată declarat este posibil să vă depistati eroarea dar doar atunci când voi sau utilizatorul final rulează aplicaţia şi în acel moment sursa erorii va fi mult mai dificil de identificat.

Cel de-al doilea motiv pentru a menţine declararea tipului de date este acela că compilatorul AS3 poate să realizeze optimizări dacă cunoaşte tipurile specifice ale variabilelor.

În PHP puteţi modifica tipul unei variabile cu fiecare atribuire:

   1: $myVar = 12; //it is an int
   2: $myVar = "now is a string";

În AS3 puteţi face acelaşi lucru (în modul strict) doar atunci când declaraţi variabila untyped utilizând “*”:In AS3 you can do the same (in strict mode) only when you declare the variable untyped using “*”:

   1: var myVar:int = 12;
   2: //this will raise an error and the application can not be compiled
   3: myVar = "this is a string";
   4:
   5: //declaring the variable untyped you can change the type with each assignment
   6: var myVar2:* = 12;
   7: myVar2 = "this is a string now";

Observaţi că folosesc cuvântul cheie var doar atunci când declar variabila. Pentru atribuiri ulterioare omiteţi var şi declararea tipului.

După cum am menţionat anterior, în AS3 variabilele sunt doar referinţe către obiectul real. Cu toate acestea, atunci când atribuiţi o variabilă de tipul int, uint, Number, Boolean, sau String altei variabile se crează o copie (acelaşi lucru se întâmplă atunci când transformăm o variabilă de aceste tipuri într-o funcţie). În PHP puteţi utiliza operatorul “&” pentru a atribui întotdeauna variabile prin referinţă chiar şi pentru tipurile de funcţii primitive; şi atunci când modificaţi valoarea pentru o variabilă cealaltă variabilă va indica aceeaşi valoare modificată.

Pentru a concatena stringuri în PHP utilizaţi “.” (punct), în AS3 utilizaţi “+” (plus):

   1: //in PHP
   2: $space = " ";
   3: $a = "this" . $space . "is!";
   4:
   5: //in AS3
   6: var space:String = " ";
   7: var a:String = "this" + space + "is!";

În PHP puteţi să definiţi variabilele oriunde doriţi: la nivelul fişierului, într-o funcţie sau într-o clasă. În cadrul aplicaţiilor Flex, variabilele pot fi declarate doar în interiorul unei funcţii sau la nivelul unei clase.

Mai mult în PHP puteţi scrie cod care nu este declarat în interiorul unei funcţii:

   1: <?php
   2:
   3: $a = 1;
   4: for ($i=0; $i<100; $i++) {
   5:     $a += $i * $a;
   6: }
   7:
   8: ?>

În AS3 nu puteţi efectua operaţii cu variabile în afara funcţiilor (deşi puteţi declara variabile în afara funcţiilor) cu o singură excepţie pe care o voi explica atunci când discutăm de clase (în capitolul „Clase”). Astfel, dacă încercaţi să rulaţi codul următor veţi obţine o eroare de compilare:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
   3:     <mx:Script>
   4:         <![CDATA[
   5:         var a:int = 1;
   6:         for (var i:int = 0; i<100; i++) { //this raises an error
   7:             a += i * a;
   8:         }
   9:         ]]>
  10:     </mx:Script>
  11: </mx:Application>

Mai jos codul este rescris pentru a putea fi compilat:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
   3:     <mx:Script>
   4:         <![CDATA[
   5:         var a:int = 1;
   6:
   7:         function calculations(a:int):int {
   8:             for (var i:int = 0; i<100; i++) {
   9:                 a += i * a;
  10:             }
  11:             return a;
  12:         }
  13:         ]]>
  14:     </mx:Script>
  15: </mx:Application>

În PHP constantele sunt declarate şi utilizate după cum urmează:

   1: //constants
   2: define("CONSTANT", "Hello");
   3: $myString = CONSTANT . ‘ world!’;

În AS3 constantele sunt declarate utilizând cuvântul cheie const (există o convenţie conform căreia constantele sunt numite cu litere mari):

   1: static const HELLO:String = "Hello";
   2: var myString:String = HELLO + " world!";

Ce anume puteţi folosi drept nume al unei variabile? În acest caz PHP şi AS3 sunt asemănătoare: atâta timp cât primul caracter al numelui este o literă sau “_” urmată de litere, cifre sau underscore operaţiile sunt permise. Exemple de nume de variabile care sunt permise în ambele limbaje: _1, _a1A, b.

În PHP există o modalitate de utilizare a unei variabile prin cunoaşterea numelui acesteia:

   1: <?php
   2: $myVar = 12;
   3: $varName = 'myVar';
   4: echo($$varName); //print 12;
   5: ?>

Puteţi obţine o funcţionalitate similară şi în AS3 utilizând metoda dinamică de accesare a membrilor (variabile/metode).

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
   3:     <mx:Script>
   4:         <![CDATA[
   5:
   6:             var myVar:int = 12;
   7:
   8:             function init():void {
   9:                 var varName:String = "myVar";
  10:                 trace(this[varName]); //output 12
  11:             }
  12:         ]]>
  13:     </mx:Script>
  14:
  15: </mx:Application>

În exemplul anterior am utilizat this pentru a face referire la obiectul curent, dar puteţi utiliza aceeaşi tehnică cu orice obiect. Voi adăuga mai multe informaţii despre acest subiect când voi discuta despre clasele dinamice.

[top]

Funcţii şi funcţii anonime (closures)

În AS3 puteţi efectua aceleaşi operaţii cu funcţii pe care le realizaţi şi în PHP şi altele câteva în plus.În primul rând în AS3 puteţi defini tipul de date al argumentelor şi tipul întors (în PHP puteţi adăuga adnotări tip doar metodelor unei clase).

   1: function calculate(x:int=0, y:int=0):int {
   2:     return x + y;
   3: }
   4: //using the function
   5: var result:int = calculate(1, 2);
   6:
   7: function calculateAverage(...arguments):Number {
   8:     var result:Number = 0;
   9:     for (var i:int=0; i<arguments.length; i++) {
  10:         result += arguments[i];
  11:     }
  12:     return result/arguments.length;
  13: }
  14:
  15: //using the function 
  16: var result:Number = calculateAverage(1, 2, 3, 4, 5, 6);

Puteţi combina … operatorul (rest) cu argumente explicite atâta timp cât aşezaţi operatorul rest ultimul din lista argumentelor: function foo(x:int, y:int, …arguments):Number {}. Operatorul rest poate fi util atunci când doriţi să creaţi funcţii cu un număr variabil de argumente.Dacă funcţia nu înapoiază nimic utilizaţi void drept tip de dată pentru valoarea returnată.

În PHP şi AS3 puteţi avea valori default pentru argumente. De exemplu:

   1: //php code
   2:
   3: function doThing($a, $b="default value") {
   4:     echo $a . $b;
   5: }
   6:
   7: //AS code
   8: function doThing(a:String, b:String="default value"):void {
   9:     trace(a + b);
  10: }

Bineînţeles că puteţi defini funcţii în interiorul unei funcţii (veţi vedea un exemplu în următorul exemplu de cod).

În al doilea rând, în AS3 orice funcţie este reprezentată sub forma unei instanţe a clasei Function. Acest aspect face posibile cateva lucruri interesante:

  • Puteţi crea o funcţie literal şi o puteţi atribui unei variabile şi apoi puteţi apela funcţia prin intermediul variabilei respective (acest lucru este posibil şi în PHP)
  • Puteţi returna o funcţie drept urmare a execuţiei unei alte funcţii
  • Puteţi pasa funcţiile ca şi argumente atunci când apelaţi alte funcţii
   1: var f:Function = function multiply(x:int, y:int):int {
   2:     return x*y;
   3: }
   4:
   5: trace(f(3,5));
   6:
   7: function giveMeAFunction():Function {
   8:     return function multiply(x:int, y:int):int {
   9:         return x*y;
  10:     };
  11: }
  12:
  13: var h:Function = giveMeAFunction();
  14: trace(h(3,4));

În PHP şi în AS3 puteţi crea funcţii anonime (sau closures). În modelul anterior de cod aţi putut observa un exemplu de concepere a unei funcţii anonime în interiorul componentei giveMeAFunction() şi de returnare a acesteia.

Poate că diferenţa cea mai notabilă între funcţiile în AS3 şi PHP constă în modalitatea de definire a acestora. În PHP puteţi defini orice număr de funcţii într-un fişier. În AS3 puteţi defini doar o singură funcţie într-un fişier şi numele funcţiei trebuie să se potrivească cu numele fişierului. De exemplu dacă definiţi o funcţie denumită doSomeMath(), trebuie să creaţi funcţia respectivă  într-un fişier denumit doSomeMath.as. În momentul în care definiţi funcţiile utilizaţi package (veţi învăţa despre package într-un capitol ulterior). Astfel, atunci când doriţi să creaţi un grup de funcţii utilitare, dacă nu aveţi de gând să le scrieţi într-un grup de fişiere puteţi crea o singură clasă şi să le definiţi drept metode statice.

[top]

OOP: clase şi interfeţe

Este momentul să trecem la caracteristicile Programării Orientate pe Obiecte ale limbajelor de programare PHP şi AS3. În PHP puteţi scrie cod orientat pe obiect si/sau cod procedural; AS3 este orientat obiect.

Să începem cu o clasă simplă PHP pentru a observa diferenţele în ceea ce priveşte sintaxa (de reţinut că folosesc PHP 5.3 ca referinţă):

   1: namespace org\corlan {
   2:
   3:     class SimpleClass {
   4:
   5:         public $public = 'Public';
   6:         protected $protected = 'Protected';
   7:         private $private = 'Private';
   8:
   9:         function SimpleClass() {
  10:
  11:         }
  12:         // Redefine the parent method
  13:         function displayVar()
  14:         {
  15:
  16:         }
  17:     }
  18: }
  19:
  20: //use the class like this
  21: require_once('flassFile.php');
  22: $obj = new org\corlan\SimpleClass();
  23: $obj->displayVar();

În AS3 aceeaşi clasă se scrie după cum urmează:

   1: package org.corlan {
   2:
   3:     public class SimpleClass {
   4:
   5:         public var _public:String = "Public";
   6:         protected var _protected:String = "Protected";
   7:         private var _private:String = "Private";
   8:
   9:         function SimpleClass() {
  10:
  11:         }
  12:
  13:         // Redefine the parent method
  14:         public function displayVar():void
  15:         {
  16:
  17:         }
  18:     }
  19:
  20: }
  21:
  22: //you use the class like this:
  23: import org.corlan.SimpleClass;
  24:
  25: var object:SimpleClass = new SimpleClass();
  26: object.displayVar();

Principalele diferenţe sunt următoarele:

  • Numirea fişierului unde este stocată clasa
    • În PHP puteţi defini o clasă într-un fişier care poate fi denumit în orice fel
    • În AS3 numele fişierului şi numele clasei trebuie să fie identice (dacă clasa este denumită SimpleClass, atunci fişierul trebuie să fie de forma SimpleClass.as)
  • Namespaces versus Package
    • În PHP puteţi utiliza namespaces cu scopul de a evita conflictele dintre nume între clasele existente
    • În AS3 utilizaţi pachetele; cu toate acestea, atunci când declaraţi o clasă care face parte, de exemplu, din pachetul org.corlan package, acest lucru înseamnă că clasa se va afla în interiorul unui folder org/corlan din folder-ul sursă Flex. Numele pachetului se traduce într-o structură a folder-ului. Pachetele utilizate împreună cu modificatorii de acces pentru tipurile de clasă pot face ca clasa să nu fie vizibilă în afara pachetului (mai multe informaţii despre acest subiect în capitolele următoare)
  • Funcţiile require/include vs. import
    • În PHP, includeţi de obicei fişierul unde este definită clasa utilizând funcţia require_once. Începând cu PHP 5 puteţi defini o funcţie __autoload() şi să includeţi require_once sau include_once în această funcţie în loc să scrieţi lista fişierelor solicitate la începutul fiecărei pagini
    • În AS3 utilizaţi o declaraţie-import pentru a include clasa dorită. Cu toate acestea, dacă doriţi să includeţi toate clasele din pachetul org.corlan puteţi scrie funcţia import utilizând wild card import org.corlan.*. O altă diferenţă constă în faptul că compilatorul AS3 va compila doar clasele care sunt efectiv utilizate în codul vostru (şi anume doar atunci când o instanţă a respectivei clase particulare este într-adevăr creată).
  • Apelarea unei metode/unui mebru sau a unei instanţe:
    • În PHP utilizaţi operatorul “->”
    • În AS3 utilizaţi operatorul “.” (punct)

Şi acum să trecem la modificatorii pentru tipurile de clasă/metode/funcţii membru.

Voi începe cu modificatorii pentru clasă:

  • PHP are final şi abstract; public este implicit, toate clasele sunt public în PHP
  • AS3 are public, internal, final şi dynamic. Dacă nu specificaţi nici un modificator de acces (public sau internal), atunci clasa este automat internal, ceea ce înseamnă că poate fi accesată doar de clasele din acelaşi pachet. public şi final au acceaşi semnificaţie în PHP; abstract nu există în AS3, dar puteţi depăşi această limitare utilizând interfeţele. Dynamic marchează clasa în sensul că poate fi modificată la rulare prin schimbarea membrilor sau prin adăugarea unor membri noi.

Modificatorii pentru proprietăţile clasei:

  • PHP sunt: public, private, protected, static
  • AS3 are modificatorii PHP şi în plus internal. Internal este utilizat pentru a pune la dispoziţie proprietăţile doar în interiorul aceluiaşi pachet. Atunci când nu se specifică niciun modificator se utilizează internal.

Modificatorii pentru metodele clasei:

  • PHP sunt public, private, protected, static, final, şi abstract.
  • AS3 sunt: public, private, protected, static, final, internal, şi override. Abstract nu există în AS3; internal pune la dispoziţie metodele doar pentru codificare în cadrul aceluiaşi pachet.

În AS3 toate operaţiile pe care le puteţi realiza cu funcţii pot fi efectuate şi cu metodele dintr-o clasă.

Constructorii definiţi în PHP pot fi marcaţi ca privaţi; puteţi defini un constructor printr-un nume similar cu denumirea clasei sau puteţi utiliza metodele speciale __construct(), __destruct(). În AS3 constructorul este întotdeauna public şi trebuie să aibă numele identic cu clasa. Dacă nu este furnizat niciunul AS3 crează unul pentru voi.

Cum sunt accesate proprietăţile statice şi metodele statice:

  • În PHP prin utilizarea ClassName::propertyName
  • În AS3 prin utilizarea ClassName.propertyName. Cu toate acestea, în AS3 în interiorul aceleiaşi clase puteţi renunţa la denumirea clasei.
   1: package org.corlan {
   2:
   3:     public class Foo {
   4:
   5:         private static myVar:String;
   6:
   7:         function Foo() {
   8:             Foo.myVar = "value 1";
   9:             myVar = "value 2";
  10:         }
  11:
  12:     }
  13: }

this:

  • În PHP utilizaţi variabila specială $this a clasei pentru a face referire la membrii clasei (variabile/metode) definiţi în cadrul aceleiaşi clase: $this->myVar = 22;
  • În AS3 utilizaţi aceeaşi variabilă this: this.myVar = 22; cu toate acestea, puteţi renunţa la this şi să folosiţi doar myVar = 22.

În AS3 doar o singură clasă poate fi declarată înt-un fişier în interiorul pachetului (şi această clasă dă numele fişierului). Cu toate acestea , în afara declarării pachetului puteţi declara oricât de multe clase doriţi:

   1: package org.corlan {
   2:
   3:     public class Foo {
   4:
   5:         private static var instance:Foo;
   6:
   7:         function Foo(object:Bar) {
   8:
   9:         }
  10:
  11:         static public getInstance():Foo {
  12:             if (Foo.instance == null) {
  13:                 Foo.instance = new Foo(new Bar());
  14:             }
  15:             return Foo.instance;
  16:         }
  17:
  18: }
  19:
  20: class Bar {}

Acest aspect are un efect interesant: toate clasele definite în cuprinsul unui fişier în afara pachetului vor fi disponibile doar codului declarat în interiorul aceluiaşi fişier. Pentru orice alt cod acestea pur şi simplu nu există. Vă amintiţi restricţia referitoare la faptul că în AS3 nu puteţi declara constructorul privat? Ei bine, prin utilizarea unei tehnici similare cu acest exemplu vă puteţi asigura că există o singură instanţă a clasei Foo. În eventualitatea în care un cod extern apelează constructorul o excepţie  va fi aruncată deoarece codul extern nu poate utiliza o instanţă a clasei Bar deoarece această clasă este invizibilă codului extern.

Mostenire

Extinderea claselor în AS3 este foarte similară cu cea din PHP. Utilizaţi acelaşi cuvânt cheie extends urmat de numele clasei pe care doriţi s-o extindeţi. Pentru a suprascrie o metodă în AS3 faţă de PHP trebuie să adăugaţi cuvântul cheie override la semnătura metodei. Supraîncărcarea (overloading) nu este suportată (nu puteţi avea două sau mai multe metode cu acelaşi nume).

În PHP accesaţi funcţiile membru ale clasei părinte utilizând sintaxa parent::memberName; în AS3 utilizaţi super.memberName. Atunci când constructorul unei clase este executat, mai întâi este apelat constructorul clasei părinte. Acest lucru se  produce chiar şi atunci când nu o apelaţi în mod explicit din codul vostru. Întotdeauna dacă aveţi cod în contructor acesta trebuie să fie după apelul la constructorul părintelui. În acest fel oferiţi o şansă clasei părinte de a fi iniţializată în mod corect astfel încât fiul să nu utilizeze membri care nu sunt încă iniţializaţi. Apelaţi constructorul clasei părinte utilizând sintaxa: super(). Să vedem cum lucrează aceste concepte: mai întâi codul PHP şi apoi codul AS3.

   1: class SimpleClass {
   2:
   3:     function SimpleClass() {
   4:         echo('SimpleClass() called');
   5:     }
   6:
   7:     function __construct() {
   8:
   9:     }
  10:
  11:
  12:     function displayVar()
  13:     {
  14:         echo "SimpleClass class\n";
  15:     }
  16: }
  17:
  18: class ExtendClass extends SimpleClass {
  19:
  20:     function ExtendClass() {
  21:         $myVar = 1;
  22:         parent::SimpleClass();
  23:         //or
  24:         parent::__construct();
  25:     }
  26:     // Redefine the parent method
  27:     function displayVar()
  28:     {
  29:         echo "Extending class\n";
  30:         parent::displayVar();
  31:     }
  32: }
   1: public class SimpleClass {
   2:
   3:     function SimpleClass() {
   4:         trace("SimpleClass() called");
   5:     }
   6:
   7:     public function displayVar():void
   8:     {
   9:         trace("SimpleClass class");
  10:     }
  11: }
  12:
  13: public class ExtendClass extends SimpleClass {
  14:
  15:     function ExtendClass() {
  16:         super(); //we have to call first the parent constructor, and only after we can execute our code
  17:         var myVar:int = 1;
  18:     }
  19:
  20:     override public function displayVar():void {
  21:         trace("overrided displayVar()");
  22:         super.displayVar();
  23:     }
  24: }

Haideţi să examinăm cum este iniţializată o clasă în AS3. Atunci când o clasă este instanţiată mai întâi sunt iniţializate toate proprietăţile apoi este executat codul static definit la nivelul clasei (acest lucru nu este posibil în PHP), şi ulterior constructorul este executat. Iată un exemplu:

   1: public class Foo {
   2:
   3:         private var a:int = 0;
   4:         private static var os:String;
   5:         trace("initializer");
   6:
   7:         if (Capabilities.os == "LINUX")
   8:             os = "LINUX";
   9:         else
  10:             os = "other";
  11:
  12:         public function Foo(a:int=1) {
  13:             trace("foo() executed");
  14:         }
  15: }
  16:
  17: var foo1:Foo = new Foo();
  18: var foo2:Foo = new Foo();
  19: //produces this output in console:
  20: initializer
  21: foo() executed
  22: foo() executed

În AS3 puteţi crea obiecte folosind constructii prototip (este asemănător cu procedura utilizată în JavaScript pentru a crea/extinde clase). Iată un exemplu simplu:

   1: //we create a function
   2: function MyClass(value:String = "Mihai") {
   3:     //we create a property
   4:     this.name = value;
   5: }
   6: //we use the special variable prototype of the function 
   7: //to create another method 
   8: MyClass.prototype.setName = function (value:String):void {
   9:     //we have access to the property defined on MyClass object
  10:     trace(this.name);
  11:     this.name = value;
  12:     trace(this.name);
  13: }
  14:
  15: //create an instance
  16: var myObject = new MyClass();
  17: //accesing the method created earlier
  18: myObject.setName("Joe");

Voi furniza mai multe informaţii despre caracteristicile dinamice ale limbajului AS3 într-un capitol ulterior.

Functii accesori (get/set)

În orice limbaj OOP utilizaţi, de obicei, get/set pentru a controla proprietăţile clasei pe care doriţi să le expuneţi în exterior. PHP nu face excepţie. Cu toate acestea, în AS3 există un suport special pentru proprietăţile care utilizează cuvintele cheie set şi get. Iată mai jos un exemplu:

   1: public class Employee {
   2:
   3:     private var _salary:int = 0;
   4:     private var _income:int = 0;
   5:
   6:     function Employee() {
   7:
   8:     }
   9:
  10:     public function set salary(value:int):void {
  11:         if (value > 0) {
  12:             this._salary = value;
  13:             this._income = this._salary * 12;
  14:         }
  15:     }
  16:
  17:     public function get salary():int {
  18:         return this._salary;
  19:     }
  20:
  21:     public function get income():int {
  22:         return this.income;
  23:     }
  24: }
  25:
  26: //using this class
  27: var emp:Employee = new Employee();
  28: emp.salary = 1000;
  29: trace(emp.income);
  30: //this raise an error, because the income property is read-only 
  31: //for the outside code
  32: emp.income = 120;

În fond, deşi am setter şi getter pentru câmpul _salary, pot apela aceste metode ca şi cum acestea ar fi câmpuri sau proprietăţi şi nu funcţii: object.salary = 20 în loc de object.salary(20). Şi dacă alegeţi să nu definiţi un setter obţineţi proprietăţi readonly. Astfel am procedat cu proprietatea _income.

Această caracteristică, în afară de un cod mai usor de urmarit, facilitează şi scrierea de librării care vor fi utilizate de alţii. Să presupunem că am ales, în exemplul meu, să creez câmpul _salary drept membru public. Dacă ulterior decid că este necesar să confirm valorile care pot fi configurate trebuie să adaug un setter. În PHP aceasta s-ar traduce printr-o funcţie de tipul myObject.setSalary(). În acest moment orice cod care utilizează clasa nu mai funcţionează; acesta trebuie actualizat pentru a utiliza setterul.

În AS3 puteţi iniţia clasa cu proprietatea definită drept public var salary:int şi atunci când decideţi că aveţi nevoie de un setter redenumiţi variabila şi adăugaţi metoda public function set salary(). Orice cod care foloseşte clasa nu este afectat de această modificare deoarece are încă access la proprietatea care utilizează aceeaşi sintaxă: objectInstance.salary = 10.

Există o convenţie în AS3 la utilizarea acestor setteri şi getteri de a adăuga underscore la numele variabilei.

Interfeţe

Interfeţele lucrează aproximativ la fel în PHP şi în AS3. Diferenţa notabilă constă în faptul că în timp ce în PHP puteţi defini metode şi constante, în AS3 puteţi defini doar metode. Cu toate acestea, puteţi defini setteri/getteri:

   1: public interface IEmployee {
   2:
   3:     public function set salary(value:int);
   4:     public function get salary():int;
   5:     public function get income():int;
   6: }

Excepţii

Ca şi PHP, AS3 are suport pentru excepţii:

   1: try {
   2:
   3: } catch(e:Error) {
   4:
   5: } finally {
   6:
   7: }
   8:
   9: //throwing an exception
  10: throw new Error("Some error");

Error este clasa parinte pentru toate erorile din AS3. Puteţi crea propriile voastre erori prin extinderea acestei clase sau puteţi utiliza sub-clasele existente.

Casting şi testarea tipului unui obiect

Uneori intenţionaţi să convertiţi automat un obiect la un alt tip sau doriţi să verificaţi tipul. Pentru verificarea tipului în PHP utilizaţi instanceof, în AS3 veţi utiliza is. Pentru a realiza un cast dispuneţi în AS3 de două sintaxe diferite.

   1: class A {};
   2:
   3: class B extends A {};
   4:
   5: var b:A = new B();
   6: //casting
   7: var c:B = b as B;
   8: //or
   9: var d:B = B(b);
  10:
  11: //checking the type of an variable
  12: if (b is A)
  13:     trace(true);
  14: if (b is B)
  15:     trace(true);

[top]

Domeniul de existenţă (scope) al variabilelor

După ce am observat modalitatea în care variabilele, funcţiile şi clasele operează în Flex şi AS 3, este momentul să discutăm despre domeniul de existentă al variabilelor. În PHP aveţi două domenii: global (variabilele definite la nivelul fişierului) şi local (variabilele definite în interiorul funcţiilor).

În Flex există cinci domenii posibile: corpul funcţiilor au forma function body, instance method body, static method body, class body şi global scope. Adăugarea modificatorilor de acces la aceste domenii (public/private/protected/internal) conferă mai multă complexitate vizibilităţii decât în PHP.

Domeniile pot cuprinde alte domenii (nested); în acest caz variabilele/funcţiile/metodele domeniului celui de mai sus devin disponibile domeniilor incluse în acesta. De exemplu, atunci când declaraţi o funcţie anonimă în interiorul corpului unei alte funcţii în AS3 toate variabilele definite în cuprinsul funcţiei externe sunt disponibile în interiorul funcţiei anonime. În PHP, trebuie să transferaţi variabilele pe care intenţionaţi să le utilizaţi sau să adaugaţi declaraţia use:

   1: //php code
   2: function a() {
   3:     $a = 1;
   4:     $b = 2;
   5:
   6:     function b() use ($a, $b) {
   7:
   8:     }
   9: }
  10:
  11: //AS3 code
  12: function a():void {
  13:     var a:int = 1;
  14:     var b:int = 2;
  15:
  16:     function b():void {
  17:         //variables a and b are available here
  18:     }
  19: }

În momentul în care declaraţi o funcţie în interiorul unui pachet nedenumit aceasta este amplasată în scopul global şi este disponibilă pentru orice cod. Cu toate acestea, orice funcţie declarată într-un fisier în afara pachetului se află tot în scopul global dar este vizibilă doar codului din acelaşi fişier.

[top]

Array-uri

Array-urile în AS3 sunt foarte asemănătoare cu acelea din PHP, cu o singură diferenţă: în AS3 un array poate avea doar indici numerici. Dacă doriţi să creaţi un array asociativ puteţi utiliza clasa Object. Dacă doriţi să creaţi un hash map în care cheile sunt obiectele (şi nu stringuri) puteţi utiliza clasa Dictionary. Creaţi un array utilizând clasa Array şi puteţi avea array-uri multi-dimensionale. Atât pentru clasa Object cât şi pentru clasa Array puteţi utiliza definiţia literală. Să urmărim câteva exemple:

   1: var myArray1:Array = new Array(1, 2, "some string");
   2: //creates an array with three elements: 0->1, 1->2, 3->some string
   3:
   4: //literal definition for an array
   5: var myArray2:Array = [1, 2, 3];
   6: //ading two more elements
   7: myArray2.push(4,5);
   8:
   9: //a hash map, similar to associative arrays in PHP
  10: var myMap:Object = new Object();
  11: myMap.name = "Flex";
  12: //literal definition of a map
  13: var myMap2:Object = {name:"Flex"};
  14:
  15: //using Dictionary class
  16: var dic:Dictionary = new Dictionary();
  17: var anObject:Object = new Object(); //creating the key
  18: dic[anObject] = "some value"; //adding a value to Dictionary

Beneficiaţi de toate metodele necesare pentru adăugarea sau eliminarea elementelor inclusiv push, shift, pop, unshift, şi splice. Concat poate fi utilizată pentru adăugarea de array-uri la un alt array. În exemplul anterior puteţi observa cum am utilizat push pentru a adăuga mai multe elemente la un array.

Array-urile nu au lungimea fixă; pot creşte pe măsură ce adăugaţi mai multe elemente. În PHP utilizaţi “[]” pentru a adăuga un element nou la sfârşitul unui array. Există o metodă similară în AS3 care utilizează proprietatea length a unui array (puteţi utiliza de asemenea proprietatea length pentru a micşora dimensiunea unui array):

   1: var array:Array = new Array();
   2: array[array.length] = 1;//array has the values: 1
   3: array[array.length] = 23;//array has the values: 1, 23

Puteţi utiliza delete pentru a sterge valoarea setată la un anumit indice: delete array[index]. Această operaţie nu va scurta lungimea unui array. Puteţi utiliza instrucţiunea for() pentru a trece printr-un array utilizând proprietatea length a acestuia. Dacă doriţi să procesaţi un Obiect (din nou acesta ar putea fi utilizat pentru a crea ceva similar cu arrayurile asociate PHP), puteţi utiliza instrucţiunile for – each (care operează similar cu construcţia din PHP) sau for – in (mai multe informaţii despre acest subiect în capitolul „Dynamic”).

[top]

Namespaces

Dacă sunteţi în căutarea echivalentului conceptuluiAS3 pentru namespaces din PHP, ar trebui să citiţi despre pachetele din secţiunea „Clase” deoarece pachetele AS3 sunt similare cu namespaces din PHP.

În ActionScript, namespace are un înţeles diferit. Să observăm pentru ce sunt utilizate şi apoi voi oferi câteva exemple:

  1. prevenirea conflictelor asociate denumirii (aveţi posibilitatea să creaţi mai multe metode cu acelaşi nume, în aceeaşi clasă, fiecare într-un namespace diferit)
  2. marcarea variabilelor şi metodelor din librării / programe pentru a sugera că sunt interne şi nu pentru a fi folosite de codul din afara librăriei (de exemplu, Flex utilizează un namespace denumit mx_internal; folosirea unui namespace în loc de private sau protected  face posibilă  utilizarea acelor metode din orice pachet şi clasă din cadrul framework-ului Flex). În acelaşi timp, dezvoltatorii sunt avertizaţi că aceste metode sau funcţii nu sunt destinate utilizării externe deoarece s-ar putea modifica în viitor)
  3. implementarea accesului pe baza permisiunilor pentru o clasă
  4. crearea unei clase care îşi poate schimba comportamentul in functie de namespace-ul selectat

Înainte de a intra în detalii, menţionez faptul că namespace-urile sunt folosite intern de Flash Player pentru a implementa modificatorii de acces: public, protected, internal şi  private.

Puteţi defini un namespace folosind această sintaxă: namespace identificator = URI. Identificatorul este ceea ce veţi folosi la declararea variabilelor metodelor şi atunci când doriţi să calificaţi o propietate sau o metodă cu scopul de a o utiliza. URI este de obicei un URL care trebuie să fie unic pentru aplicaţia voastră. Aceasta nu trebuie să existe şi, în cele mai multe cazuri, puteti utiliza numele vostru de domeniu. De exemplu, aş putea defini un namespace în felul următor: namespace online = “http://corlan.org/apps/online”.

Puteţi defini un namespace oriunde variabilele pot fi definite: la nivelul superior al definiţiei unui pachet (acesta va fi disponibil în cadrul programului), sau la nivel de clasă (acesta va fi disponibil numai în clasa în care este definit). La nivelul funcţiei puteţi utiliza numai un namespace care a fost definit în altă parte (s-ar putea să aveţi nevoie de această operaţie pentru a califica o variabilă care a fost definită în altă parte utilizând acelaşi namespace;  trebuie să cunoaşteţi URI pentru a putea face acest lucru).

Puteţi declara o metodă sau o variabilă într-un namespace dat prin aşezarea identificatorului namespace-ului înaintea declaraţiei. De exemplu: mynamespace var a:int = 1. Atunci când definiţi o variabilă sau o metodă într-un namespace, nu vi se permite să folosiţi alţi modificatori de acces (cum ar fi private de exemplu).

Pentru a apela o variabilă sau o metodă care a fost definită într-un namespace, utilizaţi operatorul “::”. Să presupunem că aţi definit o metodă denumită myMethod() într-un namespace online, puteti accesa metoda folosind  această sintaxă: objectInstance.online::myMethod(). Acelaşi lucru este valabil pentru variabile. Uneori este posibil să aveţi nevoie de mai multe variabile sau metode care au fost declarate in acelasi namespace. Puteţi deschide namespace-ul în acest scop şi puteţi elimina operatorul “::”. Puteţi realiza acest lucru utilizând directiva use namespace namespaceidentifier. De exemplu:

   1: public function doSomething() {
   2:     use namespace online;
   3:     //call the method defined in that namespace:
   4:     myMethod();
   5: }

Puteţi returna un namespace dintr-o metodă,  permiţând  codului de apelare să îl utilizeze pentru a califica o metodă sau un membru.

Haideţi să creăm două namespace-uri care pot fi folosite pentru a modifica comportamentul unei clase la rulare. În primul rând, voi defini cele două namespace-uri (voi folosi un singur fişier pentru fiecare namespace):

   1: // ActionScript file online.as
   2: package org.corlan {
   3:     public namespace online = "http://corlan.org/apps/online";
   4: }
   1: // ActionScript file offline.as
   2: package org.corlan {
   3:     public namespace offline = "http://corlan.org/apps/offline";
   4: }

Ulterior voi folosi aceste două namespace-uri pentru a crea o clasă care salvează un obiect. În funcţie de starea de conectivitate poate salva obiectul la nivel local (utilizând local storage, de exemplu) sau pe server (folosind un serviciu REST). Partea interesantă apare atunci când alt cod utilizează această clasă. Codul care apelează obiectul meu nu are idee de cum va fi stocată data şi nici nu este interesat.

Folosind aceste două namespace-uri voi crea o clasă care are două metode ambele denumite save(), fiecare dintre acestea fiind definite în câte unul dintre cele două namespace-uri. Apoi, voi folosi o variabilă de tip  privat care memorează namespace curent pentru a fi utilizat în funcţie de starea conexiunii la Internet.  Codul care foloseste obiectul meu acceseaza namespace-ul curent utilizând un getter. Aşa cum am precizat anterior programul de apelare nu cunoaşte toate aceste funcţii interne şi nu ştie despre namespace-urile definite. Să vedem codul pentru obiectul PersistObject:

   1: package org.corlan {
   2:     import flash.events.Event;
   3:
   4:     public class PersistObject {
   5:
   6:         private var _mode:Namespace = offline;
   7:
   8:         public function PersistObject() {
   9:
  10:         }
  11:
  12:         online function save(object:Object):void {
  13:             //save the object back to server
  14:             trace("online");
  15:         }
  16:
  17:         offline function save(object:Object):void {
  18:             //save the object locally
  19:             trace("offline");
  20:         }
  21:
  22:         private function connectivityChanged(e:Event):void {
  23:             //here the mode can be changed from offline to online
  24:             //and vice-versa
  25:         }
  26:
  27:         public function get mode():Namespace {
  28:             return this._mode;
  29:         }
  30:     }
  31: }

Fragmentul de cod următoar utilizează această clasă. Codul este simplu şi comentariile ar trebui să îl explice.

   1: //creating an object that we want to be stored
   2: var object:Object = {book:"Ulysses", author:"James Joyce"};
   3: //create an instance of PersitObject
   4: var persistenceObject:PersistObject = new PersistObject();
   5: //get the current namespace
   6: var currentMode:Namespace = persistenceObject.mode;
   7: //use the namespace we retrieved to qualify the save method()
   8: persistenceObject.currentMode::save(object);

Modificatori de acces ai Namespace-ului

Puteţi utiliza aceiaşi modificatori de  acces folosiţi pentru variabile sau metode: public, internal, protected şi private (pentru spaţii de nume definite la nivel de pachet puteţi utiliza doar public şi internal). Prin combinarea acestui aspect cu amplasarea definiţiei namespace-ului veţi avea un control eficient asupra vizibilităţii unui namespace dintr-un program.

[top]

Lucrul cu XML

În PHP  există suport extins pentru XML prin intermediul funcţiilor native sau a extensiilor. În AS3 există două clase care reprezintă XML: XML şi XMLList. AS3 implementează clasa XML pe baza specificaţiei W3C DOM (aveţi metode cum ar fi children(), appendChild(), parent(), insertChildBefore() şi aşa mai departe). Atunci când lucraţi cu XML este o idee bună să cunoaşteţi E4X. E4X (ECMAScript-for-XML) este o extensie a limbajului ECMA-262  care este implementată de AS3. Utilizaţi XML pentru a reprezenta un document XML. Orice nod din document este împachetat într-o ListăXML chiar şi atunci când există un singur element-copil.

Puteţi crea un obiect XML utilizând oricare dintre următoarele metode:

  1. scrieţi XML folosind forma literală
  2. creaţi o instanţă a tipului de date XML şi apoi importaţi atributul XML dintr-un fişier extern
  3. creaţi o instanţă a tipului de date XML şi utilizaţi sistemul de notaţie cu punct pentru a adăuga / modifica structura:
   1: var author:XML = <author/>;
   2: author.@id = 1; //setting an attribute called id and its value
   3: //adding two child nodes to author:
   4: author.name = "Mihai Corlan";
   5: author.article = "Flex for PHP developers";
   6:
   7: //this code is equivalent with:
   8: var author:XML = <author id="1">
   9: <name>Mihai Corlan</name>
  10: <article>Flex for PHP developers</article>
  11: </author>;

Folosind E4X puteţi găsi cu uşurinţă nodurile prin crearea condiţiilor pe baza denumirii nodurilor sau a valorii atributelor. Puteţi utiliza operatorul descendent “..” pentru a gasi toate nodurile cu un nume dat (de exemplu, pentru a gasi toate nodurile program (vedeti exemplul de mai jos) puteţi scrie: programs .. program). Puteţi crea condiţii  pe baza atributelor utilizând operatorul “@” (de exemplu, programs .. program. (@ Id == 2)). La final folosind notaţia punct puteţi naviga prin noduri (reţineţi doar că orice element-copil este tratat drept XMLList chiar şi atunci când acesta este singurul element-copil). Mai jos puteţi observa exemple de utilizare a funcţionalităţii E4X pentru lucrul cu XML.

   1: var programs:XML = <root>
   2:     <program id="1">
   3:         <name>Flex</name>
   4:     </program>
   5:     <program id="2">
   6:         <name>ActionScript 3</name>
   7:     </program>
   8:     <program id="3">
   9:         <name>AJAX</name>
  10:     </program>
  11: </root>;
  12:
  13: //retrieving the second program node and printing its name
  14: trace(programs.program[2].name[0]);
  15: //retrieving all the program nodes:
  16: var list:XMLList = programs..program;
  17: //retrieving all the program nodes that have an id attribute equal to 2
  18: var list:XMLList = pograms..program.(@id==2);

[top]

ActionScript dinamic

Vă amintiţi definiţia pentru AS3? În cuprinsul definiţiei am afirmat că AS3 este un limbaj dinamic de scripting. Să aprofundăm această  caracteristică. Dinamic se referă la faptul că un obiect poate fi modificat în timpul rulării prin adăugarea sau eliminarea  metodelor sau membrilor. Este posibil să se adauge noi metode la clasa în sine (şi orice obiect creat va avea aceste metode). Puteţi crea chiar clase noi de la zero (folosind proprietatea prototip). În AS3 există obiecte dinamice native precum Object, şi un alt exemplu în Flex este ObjectProxy.

Dacă vă întrebaţi pentru ce există această caracteristică, răspunsul este simplu: versiunile anterioare de ActionScript nu aveau toate caracteristicile şi tehnologia de programare OOP pe care AS3 le oferă azi. Din experienţa mea nu mulţi dezvoltatori utilizeaza caracteristicile dinamice ale AS3. Există două motive pentru acest lucru. În primul rând, timpul de acces pentru membrii dinamici este mai lent decât pentru membrii definiţi înainte de compilare. În al doilea rând, veţi obţine un cod care este mai predispus la erori (de exemplu, mai puţine erori pot fi depistate la compilare).

Puteţi marca o clasă definită folosind construcţiile clasice ca dinamica folosind cuvantul cheie dynamic:

   1: dynamic public MyDynamicObject {
   2:
   3: }

Apoi utilizând clasa pe care tocmai aţi definit-o puteţi adăuga membrii la rulare (amintiţi-vă că toate variabilele dinamice ale instanţei nu au tipul definit şi sunt publice):

   1: var a:MyDynamicObject = new MyDynamicObject();
   2: a.author = "Mihai Corlan";

Puteţi accesa toţi membrii unei clase dinamice utilizând  instrucţiunea for-each-in. Mai jos observaţi modalitatea prin care puteţi afişa membrii din exemplul anterior:

   1: for each (var element:* in a) {
   2:     trace(element); //displays Mihai Corlan
   3: }

Dacă doriţi să obţineţi denumirile propietatilor/metodelor în loc de valorile acestora utilizaţi bucla for-in:

   1: for (var memberName:* in a) {
   2:     trace(memberName); //outputs author
   3:     trace(a[memberName]); //outputs Mihai Corlan
   4: }

[top]

Natura asincronă a Flex-ului

Până în prezent am acoperit multe caracteristici ale platformei Flex şi multe dintre ele au fost destul de asemănătoare cu replicile lor din PHP. Cu toate acestea, natura asincronă a modului de lucru în FLEX este destul de diferită faţă de orice operaţie din PHP. Este important să înţelegeţi acest lucru.

Ce înseamnă  că Flex este asincron? Să presupunem că veţi crea o aplicaţie Flex şi după ce aplicaţia este încărcată în browser, utilizatorul poate opta să încarce imagini de pe un alt site. Puteţi utiliza clasa URLLoader pentru această sarcină. Atunci când executaţi metoda load(), pe următoarea linie de cod nu aveţi pozele disponibile. Script-ul nu se întrerupe după apelul load() () aşteptând ca datele să fie încărcate. În schimb, executarea script-ului este continuată. Ca programator vă veţi ocupa de natura asincronă folosind sistemul de evenimente. Dacă sunteţi familiarizat cu programarea AJAX această operaţie este similară cu procedura de efectuare a unui apel AJAX: înregistraţi o funcţie callback şi atunci când datele sunt primite funcţia callback este apelată şi puteţi accesa datele încărcate.

Revenind la exemplul ULRLoader ar trebui să inregistraţi o funcţie pentru a asculta evenimentul EventListener, pentru evenimentul result. Aceasta este funcţia care va fi apelată odată ce datele sunt încărcate. Iată cum ar putea arăta codul:

   1: function loadPic():void {
   2:     var loader:URLLoader = new URLLoader();
   3:     loader.dataFormat = URLLoaderDataFormat.BINARY;
   4:     //adding the event handlers or listeners
   5:     loader.addEventListener(EventComplete, picLoaded);
   6:     loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, picError);
   7:     //starting the loading
   8:     loader.load(new URLRequest("http://some_url"));
   9: }
  10:
  11: //event handler for 
  12: function picLoaded(event:Event):void {
  13:     //get the data from the loader object
  14:     //use the target property to get the loader object
  15:     (event.target as URLLoader).data;
  16: }
  17:
  18: //event handler for the error event
  19: function picError(event:IOErrorEvent):void {
  20:     //displays the error id in a pop-up windonw
  21:     Alert.show(event.errorID);
  22: }

Aş putea rezuma în felul următor: nu ne sunaţi dumneavoastră, vă vom apela noi!

Aşa cum am afirmat deja, AS3 are un sistem de evenimente încorporat. Clasa părinte  pentru toate evenimentele este Event. Toate obiectele care lucrează în mod asincron au metoda addEventListner(),  şi primele două argumente sunt tipul evenimentului, precum şi numele funcţiei care urmează să fie apelată atunci când survine evenimentul. S-ar putea crede că numai obiectele care se ocupă de adus date sunt supuse acestui model de eveniment. De fapt nu aceasta este situaţia; toate componentele sau obiectele care sunt vizuale au de asemenea evenimente. De exemplu, fiecare aplicaţie Flex are un eveniment creationComplete. Acest eveniment este declanşat odată ce toate componentele necesare din aplicaţie sunt prelucrate şi desenate pe ecran.

Deşi aţi putea considera că un astfel de cod nu este la fel de direct ca PHP există un motiv bun pentru existenţa apelurilor asincrone în Flex (şi Flash Player): Flex este o tehnologie pe partea clientului. Dacă toate apelurile ar fi sincrone, aplicaţia nu ar mai răspunde la acţiunile utilizatorului atâta timp cât datele nu au fost încarcate, de exemplu. Şi utilizatorii urăsc interfeţele pentru utilizator care nu reacţionează. Puteţi anula evenimente şi chiar modifica comportarea lor standard. Vă las să exploraţi aceste detalii pe cont propriu; ar trebui să aveţi o idee destul de bună despre noţiunea de evenimente şi intefaţa de ascultare a evenimentelor, EventListener.

[top]

Data Binding, taguri metadata şi reflexie

Data binding  reprezintă o altă caracteristică Flex care face viaţa unui dezvoltator mult mai uşoară şi în acelaşi timp reduce numărul de linii de cod. Data binding  este un mod elegant de a lega modelul de date de vizualizarea şi actualizarea automată a vizualizării pentru a reflecta orice schimbare a modelului de date. Atunci când datele sunt modificate, chiar şi în timp real, se doreşte de obicei afişarea celor mai recente date şi nu a datelor vechi.

Prin utilizarea acestei facilităţi de data binding  puteţi obţine foarte uşor acest lucru. Această facilitate de sintaxă leagă o proprietate a unui obiect (denumit sursa) de proprietatea altui obiect (denumit destinaţia); ori de câte ori se modifică sursa, destinaţia este actualizată automat.

În Flex 4 există suport pentru legarea bidirecţională (de fapt, o puteţi face în Flex 3 de asemenea dar trebuie să o declaraţi într-o etapă secundară) ceea ce înseamnă că funcţionează şi invers: atunci când destinaţia este actualizată, noua valoare este copiată înapoi în sursă. Acest lucru este util atunci când aveţi un model de date şi o formă. Legaţi modelul de date de formă şi atunci când utilizatorul schimbă  valorile  din formă data binding  bidirecţional actualizează modelul de date cu valorile formei. Este timpul să vedem nişte cod:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
   3:     <mx:Script>
   4:         <![CDATA[
   5:
   6:             [Bindable]
   7:             private var labelValue:String = "Hello World!";
   8:
   9:             private function add():void {
  10:                 labelValue += "!";
  11:             }
  12:         ]]>
  13:     </mx:Script>
  14:     <mx:Label id="myLabel" text="{labelValue}"/>
  15:     <mx:Button label="Add a !" click="add()"/>
  16: </mx:Application>

Metada Bindable pe variabila labelValue o marchează ca sursă pentru data binding. Ulterior am utilizat “{}” pentru atributul de text al etichetei pentru a marca această proprietate ca destinaţie. De aici încolo ori de câte ori este modificată variabila labelValue,  eticheta îşi actualizează vizualizarea pentru a reflecta schimbarea. Aş putea folosi aceeaşi variabilă pentru mai multe etichete sau textinput-uri şi toate vor fi actualizate pentru a reflecta noua valoare.

Există, de asemenea, o sintaxă MXML: <mx:Binding source=”labelValue” destination=”myLabel.text”/>.

Dacă doriţi să legaţi datele de un control editabil (de exemplu, o textinput) şi să copiaţi valoarea înapoi la sursă, în Flex 4 puteţi realiza legarea bidirecţională folosind operatorul “@”:

   1: <s:TextInput id="txt" text="@{labelValue}"/>

Şi dacă doriţi să utilizaţi tag-ul Binding, configuraţi atributul twoWay pe opţiunea true (din nou, acest lucru este posibil numai în Flex 4):

   1: <mx:Binding source="labelValue" destination="myTextBox.text" twoWay="true"/>

Pentru a pune în aplicare data binding compilatorul adaugă cod la compilare (amintiţi-vă că data binding  nu este o caracteristică a limbajului AS3) şi frumuseţea acestui fapt este că nu trebuie să scrieţi singuri acest cod.

Deşi data binding  oferă o modalitate directă de a lega un model de date de o interfaţă, vă veţi confrunta cu o problemă de performanţă dacă aveţi o grămadă de legături pentru variabilele care se actualizează de zeci sau sute de ori pe secundă. Pentru asemenea variabile nu este necesar să actualizaţi atât de frecvent interfaţa pentru utilizator deoarece există o limită de cadre pe secundă impuse de browser-ul în sine (undeva în jur de 50 de cadre pe secundă). Drept urmare este inutil să încercaţi să afişaţi sute de modificări pe secundă în timp real.

Un alt aspect de reţinut este faptul că nu toate obiectele pot fi surse pentru data binding. De exemplu, Object şi  Array nu pot fi; ar trebui să utilizaţi ObjectProxie şi ArrayCollection. Atunci când creaţi clase pentru a modela date, dacă doriţi ca toţi membrii clasei să poată fi surse de binding, puteţi plasa metadate Bindable la nivel de clasă în loc să le adăugaţi pentru fiecare proprietate:

   1: package org.corlan {
   2:
   3:     [Bindable]
   4:     public class VOAuthor {
   5:
   6:         public var id_aut:int;
   7:         public var fname_aut:String;
   8:         public var lname_aut:String;
   9:     }
  10: }

Să trecem acum la tag-urile de metadate (denumite si adnotări). Aţi cunoscut deja tag-urile de metadate sub formă de tag-uri Bindable. Pentru a consulta o listă completă de tag-uri pe care le puteţi utiliza cu Flex, faceţi clic aici.

În unele cazuri, tag-urile de metadate sunt folosite de compilatorul MXML în scopul de a adăuga codul necesar pentru a implementa funcţionalitate (ca şi în cazul Bindable); în alte cazuri aveţi posibilitatea să utilizaţi tag-uri de metadate pentru a da un indiciu către IDE-ul Flash Builder sau pentru a crea proprietăţi pe tag-ul MXML. Acesta este cazul  metadatelor  Event. De exemplu, să presupunem că scriu o clasă care aruncă un eveniment atunci când este încărcat un film. Pot folosi tag-ul de metadate Event pentru a  declara tipul de eveniment şi numele acestuia. Pot utiliza astfel proprietatea movieLoadedEvent pe tag-ul MXML MovieLoader pentru a înregistra o funcţie pentru ascultarea evenimentelui, EventListener. Să vedem codul clasei şi modul în care puteţi utiliza clasa în MXML.

   1: //class definition
   2: package org.corlan {
   3:     import flash.events.EventDispatcher;
   4:     import flash.events.IEventDispatcher;
   5:
   6:     [Event(name="movieLoadedEvent", type="flash.events.Event")]
   7:
   8:     public class MovieLoader extends EventDispatcher {
   9:
  10:         public function MovieLoader(target:IEventDispatcher=null) {
  11:             super(target);
  12:         }
  13:
  14:     }
  15: }
   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   3:         xmlns:local="org.corlan.*" layout="horizontal">
   4:     <mx:Script>
   5:         <![CDATA[
   6:             private function movieLoadedListener(event:Event):void {
   7:                 //do something with it
   8:             }
   9:         ]]>
  10:     </mx:Script>
  11:
  12:     <local:MovieLoader id="loader" movieLoadedEvent="movieLoadedListener(event)"/>
  13: </mx:Application>

Există şi alte lucruri interesante pe care le puteţi realiza cu aceste adnotari. Dacă configuraţi un parametru pentru compilator (keep-as3-metadata urmat de numele tag-ului) aveţi posibilitatea să adăugaţi metadate personalizate şi compilatorul va lăsa adnotarile în bytecode. Apoi puteţi folosi aceste tag-uri la runtime. De exemplu, în acest articol, puteţi citi despre utilizarea tagurilor  metadata  personalizate pentru a oferi o modalitate de a persista local un model de date într-o aplicaţie AIR (mai multe informaţii despre Adobe AIR într-un capitol viitor).

Şi aceasta mă conduce la ultimul subiect din această secţiune: reflexia. Pentru a utiliza metadate personalizate trebuie să vă bazaţi pe reflexie.

În PHP  există un API complet de reflexie implementat de urmatoarele clase: Reflection, ReflectionFunction, ReflectionParameter, ReflectionMethod şi aşa mai departe. Mai jos avem un exemplu de utilizare a clasei Reflection  pe o clasa simpla PHP:

   1: class SimpleClass {
   2:
   3:     public $public = 'Public';
   4:     protected $protected = 'Protected';
   5:     private $private = 'Private';
   6:
   7:     private function SimpleClass() {
   8:         echo('SimpleClass() called');
   9:     }
  10:
  11:     private function __construct() {
  12:
  13:     }
  14:
  15:     function displayVar() {
  16:         echo "SimpleClass class\n";
  17:     }
  18: }
  19:
  20:
  21: Reflection::export(new ReflectionClass('SimpleClass')); //this outputs:
  22:
  23: Class [ <user> class SimpleClass ] {
  24:   @@ /Applications/MAMP/htdocs/_learning/classes.php 7-26
  25:
  26:   - Constants [0] {
  27:   }
  28:
  29:   - Static properties [0] {
  30:   }
  31:
  32:   - Static methods [0] {
  33:   }
  34:
  35:   - Properties [3] {
  36:     Property [ <default> public $public ]
  37:     Property [ <default> protected $protected ]
  38:     Property [ <default> private $private ]
  39:   }
  40:
  41:   - Methods [3] {
  42:     Method [ <user> private method SimpleClass ] {
  43:       @@ /Applications/MAMP/htdocs/_learning/classes.php 13 - 15
  44:     }
  45:
  46:     Method [ <user, ctor> private method __construct ] {
  47:       @@ /Applications/MAMP/htdocs/_learning/classes.php 17 - 19
  48:     }
  49:
  50:     Method [ <user> public method displayVar ] {
  51:       @@ /Applications/MAMP/htdocs/_learning/classes.php 22 - 25
  52:     }
  53:   }
  54: }
  55:

În AS3 există trei funcţii în pachetul flash.utils care pot fi utilizate pentru reflexie: describeType(), getDefintionByNameI() şi getQualifiedSuperClassName(). Mai jos avem un exemplu al rezultatului utilizării funcţiei describeType() (rezultatul este un obiect XML):

   1: public class SimpleClass {
   2:
   3:    public var _public:String = "Public";
   4:    protected var _protected:String = "Protected";
   5:    private var _private:String = "Private";
   6:
   7:    function SimpleClass() {
   8:        trace("SimpleClass() called");
   9:    }
  10:
  11:    public function displayVar():void
  12:    {
  13:        trace("SimpleClass class");
  14:    }
  15: }
  16:
  17: function reflect():void {
  18:     var s:SimpleClass = new SimpleClass();
  19:     var description:XML = describeType(s);
  20:     trace(description);
  21: }
  22:
  23: //the output:
  24: <type name="org.corlan::SimpleClass" base="Object" isDynamic="false" isFinal="false" isStatic="false">
  25:   <extendsClass type="Object"/>
  26:   <method name="displayVar" declaredBy="org.corlan::SimpleClass" returnType="void"/>
  27:   <variable name="_public" type="String"/>
  28: </type>

[top]

Unde sunt datele mele? Aduceţi-le!

În calitate de dezvoltator PHP beneficiezi de o modalitate foarte directă de citire, prelucrare şi afişare a datelor pe ecran. Conectarea la o baza de date MySQL este unul dintre primele lucruri pe care le învaţă orice programator PHP. De fapt, mă îndoiesc că aţi reuşit să citiţi acest articol până la acest punct fără a trage cu ochiul la această secţiune.

Cum credeţi că este în Flex? Trebuie să vă dezamăgesc pentru că nu aveţi acces direct la datele memorate într-o bază de date. Dar există şi aspecte utile, bănuiesc, pentru că puteţi continua să scrieţi fişierele PHP pentru a citi/scrie date în baza voastră de date chiar şi atunci când scrieţi aplicaţii Flex.  . De ce nu există nicio modalitate directă de citire a datelor dintr-o bază de date? Din cauza vechiului  proverb “Never trust the client!” Să presupunem că aplicaţia client este o componentă Flex care ştie cum să se conecteze la serverul MySQL. Cum stocaţi userul şi parola pentru accesul la baza de date astfel încât să nu fie uşor de sustras din fisierul SWF şi să aveţi baza de date compromisă? Configuraţi un alt utilizator/o altă parola pentru fiecare utilizator şi le oferiţi aceste informaţii? Acesta este doar unul dintre motivele pentru care nu este o idee bună să aveţi o tehnologie-client care se poate conecta direct la un server de baze de date, fără a utiliza un server de aplicaţii intermediar.

Practic, în aplicaţiile Flex vă bazaţi pe scripturi de pe server pentru a gestiona baza de date. Flex vă oferă o modalitate de a apela scripturi PHP aflate pe server şi de a recupera răspunsul în Flex. Există trei moduri diferite de a vă conecta la o sursă de date de pe server: servicii de tip REST style, Servicii Web şi servicii remoting (sau RPC).

flex_php_10

Puteţi utiliza clasa HTTPService pentru a utiliza serviciile REST style. Puteţi trimite variabile POST atunci când efectuaţi o cerere şi răspunsul poate fi XML, JSON (există o librărie AS3 pentru lucrul cu JSON) sau formatul propriu.

Dacă aveţi servicii  web pe server (SOAP/WSDL), puteţi utiliza clasa WebService.

Dar metoda cea mai interesantă este remoting (folosind clasa RemoteObject). Există trei motive datorită cărora sunt convins că este cea mai bună metodă. În primul rând, puteţi accesa orice clasă PHP pe care o aveţi pe server prin apelarea oricărei metode publice. Practic, din Flex utilizaţi o instanţă a funcţiei RemoteObject ca şi cum ar fi clasa PHP aflata pe server. În al doilea rând, aveţi posibilitatea să mapati modelul de date din PHP la un model de date ActionScript  şi să beneficiaţi de realizarea conversiei dintr-unul in altul în mod automat.

Acest lucru este extrem de important deoarece atunci când utilizaţi obiecte strong type obţineţi beneficiile verificărilor la compilare. Şi în al treilea rând formatul folosit de remoting pentru a serializa mesajele – AMF3 (Action Message Format) este un format binar care poate fi mult mai rapid şi mai compact în comparaţie cu SOAP/XML/JSON, în special pentru seturi mari de date. Formatul în sine este open şi oricine poate citi documentaţia şi poate crea programe care să-l folosească.

AMF3 este mai rapid deoarece comprimă datele. De exemplu, în cazul în care se repetă aceeaşi secvenţă dintr-un set de date, atunci este stocată o singură dată şi toate celelalte instanţe sunt stocate ca referinţe. Dacă un număr nu necesită 4 octeţi atunci sunt utilizaţi doar biţii necesari stocării numărului.

flex_php_11

James Ward de la Adobe a creat un test interesant care arată diferenţele dintre remoting şi alte metode. Remoting-ul este implementat nativ în Flex; pe partea serverului avem însa nevoie de o librărie care înţelege AMF3 şi remoting, deci nici în PHP nu există suport nativ pentru remoting. Acesta este motivul pentru care aveţi nevoie de o bibliotecă pe server. Există patru biblioteci disponibile, toate sunt gratuite şi am scris tutoriale despre cum se utilizează fiecare dintre ele:  Zend AMF, PHPAMF, WebORB for PHP, SabreAMF. Şi aici, puteţi citi un articol care le compară.

Deoarece tipurile de date sunt convertite în mod automat (tipul PHP în tip AS3 şi invers), trebuie să fiţi atenţi la modalitatea în care tipurile de date dintr-un limbaj sunt convertite celalat limbaj. Aici puteţi găsi un exemplu privind corespondenţa dintre tipurile de date în bibliotecă AMFPHP.

[top]

Autentificarea utilizatorului în proiecte Flex şi PHP

Cum se poate realiza autentificarea utilizatorului în aplicaţiile Flex şi PHP? Răspunsul este foarte simplu: ca şi în cazul site-urilor web realizate cu PHP utilizaţi o sesiune şi o modalitate oarecare pentru a valida utilizatorul / parola.

Practic ori de câte ori se efectuează un apel din Flex, ID-ul sesiunii este automat adăugat la cererea trimisă serverului. Astfel, în cazul în care utilizatorul a fost autentificat în prealabil se va utiliza aceeaşi sesiune.

Mai multe informaţii despre acest subiect găsiţi aici.

[top]

Lucrul cu proiecte Flex şi PHP

Din fericire atât tehnologiile PHP cât şi Flex sunt mature, prin urmare aveţi o mulţime de opţiuni atunci când vine vorba de instrumente. Vă voi prezenta  unele dintre ele în cuprinsul acestui capitol.

[top]

Flex SDK şi editori text

Prima opţiune pe care o puteţi lua în considerare este utilizarea în mod gratuit a platformei open source Flex SDK, mai ales dacă vă plac instrumentele pentru linia de comandă şi editoarele de text ca vi . Puteţi scrie codul în editorul de texte favorit  şi puteţi utiliza instrumentele pentru linia de comandă pentru a compila /depana aplicaţia.

[top]

Flex Builder / Flash Builder şi Eclipse PDT / Zend Studio

Personal prefer să folosesc un IDE modern. Probabil cea mai bună combinaţie pentru proiecte Flex şi PHP este Flex Builder sau Flash Builder 4 şi Zend Studio. Flex Builder este denumirea dată pentru IDE-ul pentru Flex de la Adobe până la versiunea cu numărul patru, a patra versiune a fost redenumită Flash Builder 4. Acest IDE este bazat pe Eclipse, este disponibil pentru Windows şi Mac OS şi este oferit sub forma unei versiuni plug-in şi a unei versiuni independente. De exemplu, dacă aveţi Zend Studio puteţi lua în considerare plugin-ul Flash Builder şi puteţi instala acest plug-in peste Zend Studio. Puteţi folosi Flex Builder 3 pentru 60 de zile (versiunea de încercare); Flash Builder 4 se află în versiunea beta în prezent (vara anului 2009). Dacă sunteţi profesor sau student puteţi obţine o licenţă în mod gratuit pentru Flex Builder/Flash Builder.

Dacă preferaţi să lucraţi cu Eclipse PDT, puteţi utiliza aceeaşi abordare: instalaţi versiunea plug-in pentru Flash Builder 4 sau invers, instalaţi PDT peste programul autonom Flash Builder.

Flash Builder 4 are “wizards” pentru lucrul cu PHP şi Flex: acesta poate analiza codul PHP şi poate genera codul AS3 şi Flex (aici se găseşte un tutorial pe această temă). Puteţi din IDE depana, compila şi lansa aplicaţia (web sau AIR). Puteţi, de asemenea, exporta aplicaţia pentru producţie (fără codul necesar depanării) şi există suport pentru refactorizare precum şi pentru design view pentru MXML, pentru lucrul cu states si multe altele.

De asemenea, se integrează cu Flash Catalyst, astfel încât să puteţi crea designul aplicaţiei în Flash Catalyst şi apoi să deschideţi proiectul generat în Flash Builder 4 şi să continuaţi să adăugaţi logica aplicaţiei (puteţi vedea această înregistrare video pentru a observa cum se poate crea o bară de derulare verticală utilizând Adobe Illustrator, Flash Catalyst şi Flash Builder 4).

Există şi alte IDE (produse comerciale) pentru Flex: IntelliJ IDEA şi FDT (pe baza mediului de dezvoltare Eclipse).

[top]

Depanarea aplicaţiilor Flex

Puteţi depana codul Flex folosind un suportul de depanare din SDK-ul de Flex sau de la Flash Builder 4 (sau Flex Builder 3). Dacă aţi ales o configurare compusă din Flash Builder 4 şi Zend Studio, atunci puteţi depana foarte uşor codul PHP şi FLEX din acelaşi proiect. Puteţi efectua un apel din Flex către PHP şi puteţi începe sesiunea de depanare în PHP; apoi, atunci când răspunsul din PHP ajunge in Flex  intraţi în sesiunea de depanare Flex. Aici şi aici sunt disponibile clipuri video privind acest subiect, şi aici este un tutorial pentru Eclipse PDT şi Flex Builder.

Una dintre primele abordări practicate de mine în PHP acum ani de zile atunci când aveam erori era să folosesc o combinaţie de die () şi var_dump () pentru a vedea ce se întâmplă. În AS3 puteţi utiliza trace () pentru a tipări valorile variabilelor în consolă. Lucrul interesant este că atunci când compilaţi aplicaţia pentru producţie toate declaraţiile trace () sunt eliminate. Acesta reprezintă un mod  neobstructiv de a depăna; puteţi utiliza, de asemenea, clasa Alert pentru a afişa mesajele într-o fereastră pop-up (similar cu depanarea Javascript înainte de existenţa lui Firebug).

Elementul-cheie de reţinut  este următorul: în prezent aveţi un client care este separat de server iar problemele pot surveni de partea clientului, de partea serverului sau la nivelul reţelei.

[top]

What is Adobe AIR

Adobe AIR este o platformă ce asigură un mediu de rulare pentru aplicaţii tip RIA care rulează ca aplicaţii desktop în Windows, Mac, şi Linux (deci fară a necesita un browser web). Cu AIR puteţi crea o singură aplicaţie care poate rula pe oricare dintre aceste sisteme de operare. Exemple de aplicaţii AIR: Tour de Flex, TweetDeck, Times Reader, Dojo Toolbox, şi Sideline from Yahoo!. flex_php_12

Vă puteţi gândi la Adobe AIR ca la un “Flash Player” pentru desktop. Cu toate acestea, Adobe AIR este mai mult decât un Flash Player modificat.

În cuprinsul acestei rulări există un motor HTML (WebKit, acelaşi motor folosit de Safari şi Google Chrome), precum şi un Flash Player modificat. Aceste două motoare oferă un set de API-uri care asigură acces la maşina pe care aplicaţia AIR rulează. Există API-uri pentru scrierea / citirea fişierelor de pe disc, detectarea conectivităţii la reţea, detectarea numărului de monitoare conectate şi a rezoluţiei, actualizări ale aplicaţiei, notificări, bazele de date locale, funcţia „drag and drop”, şi multe  altele.

flex_php_6

În calitate de dezvoltator web, puteţi alege orice combinaţie dintre următoarele tehnologii: Flex, ActionScript 3, sau HTML/CSS/JavaScript pentru a crea o aplicaţie AIR. Într-adevăr utilizând doar HTML, JavaScript şi CSS, de exemplu, puteţi crea o aplicaţie AIR. De fapt, Dojo Toolbox şi aplicaţia Sideline de la Yahoo! sunt create folosind HTML/CSS/JS.

Prin urmare, puteţi refolosi prin intermediul AIR abilităţile existente (de web developer) pentru a construi aplicaţii pentru desktop. Dar de ce aţi dori să creaţi o aplicaţie web care să ruleze ca o aplicaţie pentru desktop? Exista mai multe motive pentru aceasta:

  • doriţi să fiţi în măsură să utilizaţi aplicaţia, sau părţi ale acesteia, atunci când nu aveţi o conexiune la Internet
  • doriţi să eliminaţi chrome-ul browser-ul şi să particularizaţi în întregime înfăţişarea aplicaţiei voastre
  • doriţi să  puteţi integra aplicaţia cu alte aplicaţii de pe computerul utilizatorului (de exemplu, pentru a pune în aplicare funcţia „drag and drop” pentru fişiere luate din aplicaţia AIR şi lăsate pe desktop şi invers)
  • doriţi să puteţi păstra fişiere pe maşina utilizatorului
  • doriţi să construiţi un sistem de notificare şi doriţi să rulaţi aplicaţia micşorată în taskbar sau dock (de exemplu,  aplicaţiile de mesagerie instant vă pot notifica atunci când un nou mesaj este primit deşi acestea sunt minimizate)

Pentru dezvoltarea de aplicaţii AIR, puteţi folosi în mod gratuit AIR SDK (aveţi instrumente pentru linia de comandă pentru construire, testare şi depanare), puteţi utiliza Aptana Studio (dacă doriţi să creaţi aplicaţii AIR folosind HTML/JS/CSS), sau puteţi utiliza Flash Builder 4 (sau Flex Builder 3).

În cele din urmă, orice aplicaţie Flex care a fost creată pentru browser poate fi transformată într-o aplicaţie AIR în cel mai scurt timp. Desigur, dacă vă opriţi aici şi nu utilizaţi caracteristicile specifice AIR,  nu are nicio logică pentru că nu aţi furnizat nicio valoare suplimentară fata de versiunea web.

[top]

Ce urmează?

La începutul următorului an va fi lansat Flex 4. Adobe a dezvoltat un nou instrument (acesta este încă în versiune beta) numit Flash Catalyst care poate fi folosit pentru a transforma desenele statice create în Photoshop sau Illustrator în interfeţe funcţionale Flex. Imaginaţi-vă un instrument care ar putea încărca ca date de intrare un fişier Photoshop sau Illustrator şi ar produce un cod  HTML/CSS /JavaScript şi care ar păstra aspectul fişierelor de intrare. Aceasta este ceea ce Flash Catalyst  face, numai că produce cod Flex 4 şi nu HTML.

În acelaşi timp, ne concentrăm intens să facem Platforma Flash disponibilă pe toate ecranele: de la computere la dispozitivele mobile, de la net-pcuri la televizoare. În prezent avem Flash Lite 3 disponibil pe telefoane mobile (Nokia, Sony Ericsson, HTC, Android, Palm). Anul viitor vom lansa versiunea mobilă a lui Flash Player 10, Flash Player 10.1. De asemenea, este foarte posibil ca anul viitor să fim martorii primelor televizoare cu suport pentru Flash. Cât de interesant ar fi să avem o interfaţă pentru utilizator care să profite de toate caracteristicile Flash Player sau să permită vizionarea unor clipuri HD de pe web (Flash are suport pentru H-264 standard). Unii analişti consideră că vor exista mai multe telefoane mobile conectate la Internet în viitorul apropiat decât calculatoare, şi mulţi oameni vor folosi dispozitivele lor mobile ca mijloc principal pentru accesarea conţinutului de pe Internet neavând  un computer la dispoziţie.

Ce înseamnă acest lucru pentru un dezvoltator web? Aceasta înseamnă că aveţi posibilitatea să extindeţi domeniul dumneavoastră de expertiză şi serviciile furnizate de la site-uri Web la aplicaţii RIA pentru desktop (utilizând Adobe AIR) şi de la computere la telefoane mobile şi alte dispozitive cu ecrane. Desigur, pentru a putea face acest lucru trebuie să învăţaţi lucruri noi, dar nivelul de complexitate nu este nici măcar pe aproape de cerinţele necesare pentru a deveni expert în C sau C ++ pentru o anumită platformă.

[top]

Care este următorul pas

Sper că aţi găsit răspunsuri la câteva din întrebările voastre. Dacă sunteţi hotărât să intraţi în lumea Flex aici puteţi găsi unele resurse:

Flex User Groups

Există Flex User Groups in Bucureşti, Craiova, Timişoara şi Cluj. Unele din ele au şi pagină virtuală pe Adobe Groups, organizează întruniri aproape lunar unde sunt sesiuni şi pentru începători şi avansaţi. Puteţi vorbi cu programatori care deja işi câstigă existenţa “făcând” Flex.

Tour de Flex

Consider Tour de Flex drept versiunea Web 2.0 sau RIA  a îndrăgitului php_manual.chm . Puteţi să îl instalaţi de aici. Are exemple privind modul de utilizare a oricărei componente în Flex (puteţi vedea cum arată şi codul necesar). De asemenea aveţi acces facil la documentaţia Flex. Aplicaţia însăşi este creată folosind Flex şi Adobe AIR.

flex_php_7

Cărţi

Există multe cărţi despre Flex şi ActionScript 3. Cu toate acestea, favoritele mele personale dar şi cele pe care le recomand de obicei sunt urmatoarele:

  • Flex 4 in a Day – well this is not exactly a book. It is a 40-page documentation on Flex 4 that once read it, it should give you a good overview over Flex 4
  • First steps in Flex, de Bruce Eckel şi James Ward (evanghelist tehnic la Adobe); această carte vă oferă o imagine de ansamblu asupra modului în care puteţi utiliza Flex pentru dezvoltarea de aplicaţii web şi pentru desktop şi o puteţi citi într-un singur week-end.
  • Essential ActionScript 3 de Colin Moock, aceasta este o carte groasă şi trebuie să fii un cititor excelent pentru a termina cartea într-un singur week-end. Deşi nu epuizează toate aspectele asociate platformei Flex , puteţi afla aproape totul despre ActionScript 3.

flex_php_8 flex_php_9

Site-uri Web

Există sute de site-uri web şi blog-uri care cuprind informaţii despre Flex şi ActionScript 3. Ar fi imposibil să vă ofer o listă completă dar voi menţiona câteva dintre preferatele mele:

  • Adobe Developer Connection. Un loc excelent pentru a citi articole tehnice despre Flash, Flex, şi AIR. Site-ul este actualizat săptămânal. Există un capitol dedicat Flex-ului şi PHP.
  • Adobe TV. Acest site vă oferă acces la foarte multe clipuri video cu prezentări de la conferinţe şi tutoriale video.
  • Gotoandlearn.com. O colecţie excelentă de tutoriale video ale colegului evanghelist  Lee Brimelow.
  • Flex documentation. Reţineţi că puteţi descărca un fişier ZIP al acestei documentaţii. Puteţi găsi aici  resurse în diverse formate.
  • Adobe Groups. O platformă gratuită unde puteţi găsi Grupuri de utilizatori Adobe (inclusiv grupuri Flex sau Flash). Aruncaţi o privire, ar putea fi un Grup de utilizatori Flex în zona voastră  şi de obicei se organizează întâlniri lunare. Există forumuri pe această platformă, deci există conţinut si in romana.
  • My blogroll.Verificaţi acest site; cei mai mulţi dintre ei sunt persoane de la Adobe care scriu despre Flash şi Flex.
  • Aruncaţi o privire la  lista pe care o întreţin cu framework-uri, biblioteci, precum şi alte resurse Flex.

Şi acum, cred, puteţi înţelege de ce atunci când un programator mă întreabă ce este Flex mă uit în gol  pentru un timp. În acest timp, toate miile de cuvinte scrise aici îmi  trec prin faţa ochilor … sunt atât de multe lucruri de spus, ce naiba aş putea spune într-o singură frază!? Din fericire, acum pot raspunde “Flex este minunat, amice! Citeşte acest articol!”.

Dacă aveţi comentarii, vă rog lasati unul pe această pagină. Mulţumesc!

[top]

3 thoughts on “Flex pentru programatorii PHP

  1. Excelent articol! a fost o placere lectura, pentru ca am facut-o în limba maternă. Va multumesc.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>