CATEGORII DOCUMENTE |
Prezentul articol va ilustra implementarea principalelor concepte ale programarii obiectuale, in contextul procesarii documentelor XML.
Limbajul PHP, mai ales de la versiunea 4, ofera implementarea unora dintre cele mai importante aspecte ale programarii obiectuale: incapsularea datelor, mostenirea, polimorfismul. Astfel, PHP da posibilitatea programatorului sa exprime distinctia dintre proprietatile generale si cele specifice ale obiectelor cu care lucreaza. Vom ilustra aceste caracteristici prin cateva exemple concludente.
Incapsularea datelor reprezinta un mecanism de protectie a membrilor de tip data, accesul la ei realizandu-se exclusiv prin intermediul unor metode specifice si nu in mod direct. Acest lucru se realizeaza prin intermediul claselor, dupa cum se poate remarca din fragmentul de cod PHP de mai jos:
<?php |
class Student |
function getYear() |
?> |
Datele-membru se definesc utilizand var, putand avea orice tip (intreg, tablou sau chiar obiect). Metodele se specifica prin declaratii de functii care prelucreaza membrii clasei. Pentru a accesa datele clasei, metodele vor trebui sa se foloseasca de constructia $this->variabila, altfel variabila se considera a fi locala in cadrul acelei metode.
Vom crea un obiect prin operatorul new, exact ca in limbajul C++:
$stud = new Student; |
Accesarea metodelor clasei se realizeaza astfel:
$stud->setYear(4); |
$student_year = $stud->getYear(); |
Din pacate, membrii data ai clasei pot fi accesati direct, neputandu-i declara privati. La fel, metodele nu pot fi specificate private sau protejate, asa cum se intampla la C++. Astfel, PHP ofera doar suport pentru incapsulare, dar nu o poate impune.
Pentru functiile membru, in loc de constructia sintactica '->', in PHP 4 se permite ' '. Astfel, codul de mai sus este echivalent cu:
$student_year = $stud::getYear(); |
Mostenirea reprezinta posibilitatea folosirii datelor sau metodelor definite in prealabil de o anumita clasa in cadrul unei clase derivate din prima. Relatia de derivare se specifica prin cuvantul-cheie extends
<?php |
class GoodStudent extends Student |
function getPrizes() |
?> |
Putem scrie urmatoarele linii:
$goodstud = new GoodStudent; |
// apel de metoda din clasa de baza |
$goodstud->setAge(21); |
// apel de metoda din clasa derivata |
$goodstud->setPrizes(2); |
In PHP mostenirea multipla nu este inca posibila. Nu putem avea, de exemplu:
class GreatStudent extends GoodStudent Genius |
Putem insa redefini o metoda in clasa derivata. In PHP 3, daca declaram un membru-data in clasa derivata avand acelasi nume ca un membru-data al clasei de baza, atunci nu mai putem accesa membrul-data din clasa de baza, el fiind 'ascuns' de membrul-data al clasei derivate. In PHP 4, pentru a accesa membri ai clasei parinte ne vom folosi de constructia ' ' (exact ca si in C++).
PHP permite specificarea constructorilor, ei fiind metode cu acelasi nume al clasei din care apartin, fiind apelati automat atunci cand instantiem un obiect al clasei respective. Putem avea de exemplu:
<?php |
class Student |
// metode |
function setYear($y) |
function getYear() |
?> |
Asadar, acum se poate crea un obiect de genul:
$stud = new Student(3, 24, 'Radu Filip'); |
Constructorii si metodele, fiind functii PHP obisnuite, pot avea specificate valori implicite pentru argumente (ca in C++):
function Student($y = '4', $a = '22', $n = '') |
Daca scriem in acest mod constructorul, atunci in urmatoarele cazuri vom avea:
// year = 4, age = 22, name = '' |
$stud = new Student(); |
// year = 2, age = 22, name = '' |
$stud = new Student(2); |
// year = 2, age = 20, name = '' |
$stud = new Student(2, 20); |
Atunci cand un obiect al unei clase derivate este creat, numai constructorul lui propriu va fi apelat, constructorul clasei de baza nefiind apelat implicit. Daca dorim ca si constructorul clasei parinte sa fie apelat, o vom face intr-o maniera explicita:
<?php |
function GoodStudent |
?> |
Daca in PHP 3, constructorii puteau avea drept orice tip de parametri, incepand cu versiunea 4, tipurile permise pentru parametrii unui constructor sunt doar cele simple (intregi, siruri de caractere), deci nu vor putea fi executate transmiteri de tablouri sau de obiecte.
Daca o clasa derivata nu poseda propriul ei constructor, va fi apelat implicit constructorul clasei parinte.
Mecanismul obiectual in PHP nu permite declararea destructorilor si nici specificarea de clase abstracte (desi se pot imagina metode mai mult sau mai putin sofisticate pentru a le simula).
Supraincarcarea (asocierea de semantici diferite unei aceleasi functii pe baza tipurilor parametrilor specificati) nu este suportata nici ea. Putem insa supraincarca, indirect, constructorii prin crearea de obiecte diferite in functie de numarul de argumente specificate:
<?php |
class Student |
function Student1($x) |
function Student2($x, $y) |
?> |
Vom putea scrie:
$stud1 = new Student('1'); // va apela Student1 |
$stud2 = new Student('1', '2'); // va apela Student2 |
Pentru a pasa un numar variabil de parametri unei functii si a-i folosi ulterior putem sa ne slujim de functiile predefinite func_get_args() func_num_args() si func_get_arg()
Astfel, functia Student() de mai sus va putea afisa toti parametrii transmisi prin codul urmator:
function Student() |
Polimorfismul reprezinta abilitatea unui obiect de a determina care metoda trebuie invocata pentru un obiect pasat ca argument in momentul rularii si acest lucru se realizeaza foarte usor in limbaje interpretate precum PHP.
Vom ilustra acest concept si implementarea lui in PHP presupunand ca avem o clasa Figure desemnand o figura geometrica in care se defineste metoda draw() si clasele derivate Circle si Square unde vom rescrie metoda draw() in functie de figura dorita a fi desenata:
<?php |
function drawing($obj) |
// coordonate centru si raza |
$circle = new Circle(100, 100, 33); |
// coordonate stanga-sus si latura |
$square = new Square(100, 200, 74); |
// afiseaza cele doua figuri |
$board = drawing($circle); // apeleaza draw() din Circle |
$board = drawing($square); // apeleaza draw() din Square |
?> |
PHP nu suporta obiecte serializate (care isi pastreaza starea si functionalitatea de-a lungul mai multor invocari ale aplicatiei, prin intermediul stocarii intr-un fisier/baza de date si incarcarea lor ulterioara). In PHP prin serializare (functiile serialize() si unserialize()) se vor salva numai membrii-data, nu si metodele, insa putem serializa tablouri asociative sau indexate, ceea ce reprezinta totusi un avantaj.
Incepand cu PHP 4, se pun la dispozitia programatorului o serie de functii folositoare:
get_class() va returna numele unui obiect, instanta a unei clase;
get_parent_class() furnizeaza clasa parinte din care provine un anumit obiect;
method_exists() testeaza daca exista o metoda pentru un anumit obiect specificat;
class_exists() testeaza existenta unei clase;
is_subclass_of() va determina existenta unei relatii de mostenire dintre doua clase.
O alta facilitate este cea a transmiterii prin referinta a parametrilor si nu prin valoare, cum se realizeaza in mod implicit. Pentru a fi transmis prin referinta, vom prefixa numele acelui parametru cu caracterul ampersand '&
Cele de mai sus ne permit sa realizam o procesare eleganta a documentelor XML, folosind SAX ori DOM.
Elaborat de James Clark, procesorul Expat este deja incorporat in serverul Apache incepand cu versiunea 1.3.9, iar in PHP este inclus de la versiunea 3.0.6. Analiza XML este bazata pe evenimente, fiecare tip de nod al arborelui asociat documentului XML declansand un anumit eveniment care va trebui tratat de o functie definita de programator. Pentru a atasa functii evenimentelor XML, ne vom folosi de o serie de functii predefinite:
xml_set_element_handler() stabileste functiile care vor fi apelate pentru procesarea elementelor XML (pentru tag-urile de inceput si de sfarsit);
xml_set_character_data_handler() stabileste functia care va fi apelata atunci cand analizorul intalneste un nod de tip CDATA (text);
xml_set_processing_instruction_handler() defineste functia care va fi executata la aparitia unei instructiuni de procesare.
Alte functii importante puse la dispozitie sunt:
xml_parser_create() initializeaza analizorul XML si returneaza o instanta a sa;
xml_parser_free() elibereaza memoria alocata analizorului;
xml_set_object() stabileste adresele functiilor care vor fi utilizate de analizor pentru a realiza procesarea documentului XML dorit;
xml_parser_set_option() se foloseste la setarea unor optiuni de analiza XML (e.g. modul de tratare a scrierii cu majuscule sau minuscule a tag-urilor);
xml_get_error_code() furnizeaza codul de eroare in urma esecului procesarii.
Pot fi amintite, de asemeni, functiile dand mai multe amanunte despre erorile survenite in timpul analizei: xml_error_string() si xml_get_current_line_number(). Functia xml_parse() returneaza, in caz de esec, o serie de coduri de eroare ale caror constante simbolice predefinite pot fi consultate in manualul PHP.
Vom defini o clasa pe care o vom folosi ulterior la procesarea documentelor XML (vom salva acest cod in fisierul parseXML.php
<?php |
// o clasa pentru prelucrarea documentelor XML |
class parseXML |
// destructor |
function destroy() |
// metode |
// seteaza tag-urile de inceput |
function set_open_tags($tags) |
// seteaza tag-urile de sfarsit |
function set_close_tags($tags) |
// seteaza numele fisierului XML |
function set_xml_file($file) |
// furnizeaza codul HTML generat |
function get_html_code() |
// tratarea evenimentului de |
// aparitie a unui tag de inceput |
function start_element($parser, $name, $attrs) |
// tratarea evenimentului de |
// aparitie a unui tag de sfarsit |
function end_element($parser, $name) |
// tratarea evenimentului de |
// aparitie a unui element de tip CDATA |
function character_data($parser, $data) |
// tratarea evenimentului de |
// aparitie a unei instructiuni de procesare |
function processing_instruction($parser, $target, $data) |
// functia de analiza propriu-zisa |
function parse() |
} /* while */ |
} /* parse() */ |
} /* class */ |
?> |
Folosind aceasta clasa, putem transforma un document XML in cod HTML, dupa cum se poate remarca din exemplul de mai jos, unde va fi prelucrat un fisier XML continand impresii despre un anumit site Web:
<?php |
// necesita prezenta clasei definite mai sus |
require('parseXML.php'); |
// substitutia tag-urilor XML cu cod HTML |
// se folosesc doua tablouri asociative |
$open_tags = array( |
'impresii' => 'n<!-- generat de parseXML -->n' . |
'<table cellpadding='5' align='center' border='1'>', |
'impresie' => '<tr align='center'>', |
'nume' => '<td><h4>', |
'ocupatia' => '<td><p style='color: blue'>', |
'virsta' => '<td><p><i>', |
'text' => '<td bgcolor='#EEEEEE'><p align='justify'>'); |
$close_tags = array( |
'impresii' => '</table>n' . |
'<!-- sfarsitul generarii parseXML -->n', |
'impresie' => '</tr>', |
'nume' => '</h4></td>', |
'ocupatia' => '</p></td>', |
'virsta' => '</i></p></td>', |
'text' => '</p></td>'); |
// instantiaza si initializeaza analizorul |
$parser = new parseXML(); |
$parser->set_xml_file('impresii.xml'); |
$parser->set_open_tags($open_tags); |
$parser->set_close_tags($close_tags); |
// ruleaza analizorul |
$parser->parse(); |
// afiseaza rezultatul |
echo $parser->get_html_code(); |
// distruge obiectul |
$parser->destroy(); |
?> |
Clasa definita este suficient de generala pentru a putea fi utilizata pentru orice tip de document XML. Tag-urile netratate de programul nostru vor fi ignorate.
De multe ori insa ar fi de dorit sa realizam anumite prelucrari asupra datelor stocate de fisierele XML. Putem inca sa ne slujim de parseXML. De exemplu, am dori ca utilizatorul (sau autorul site-ului) sa poata trimite mesaje celor care si-au lasat impresiile. Pentru aceasta vom defini o clasa derivata din clasa parseXML si vom redefini functiile start_element() si end_element()
<?php |
require('parseXML.php'); |
// folosirea mostenirii pentru a defini |
// un alt comportament |
class parseXML2 extends parseXML |
else |
$this->is_email = 0; |
function end_element($parser, $name) |
// apeleaza metoda din clasa de baza |
parseXML::end_element($parser, $name); |
?> |
Noul membru de tip data is_email este folosit pentru a putea inchide corect tag-urile elementului <a> (se poate intampla ca atributul email sa nu apara). Restul codului ramane acelasi, in loc de $parser = new parseXML() trebuind fi scrisa linia $parser = new parseXML2()
O posibila rulare a scriptului PHP de mai sus poate avea ca efect urmatoarea pagina Web:
Desigur, daca facem numai prelucrari asupra documentelor XML, ne putem dispensa de definirea celor doua tablouri asociative open_tags[] si close_tags[], iar in functiile startElement() si endElement() putem insera orice cod dorim.
Utilizand tehnicile descrise mai sus, studentii Constantin Gheorghita, Valentin Pascareanu si Dan Torin au realizat o aplicatie Web bazata pe PHP pentru managementul lucrarilor de licenta la Facultatea de Informatica a Universitatii 'Al.I.Cuza' din Iasi. Datele referitoare la licenta sunt stocate intr-un fisier XML avand formatul de mai jos (lasam cititorului placerea de a construi DTD-ul pentru validarea acestui document):
<database> |
<record> |
<!-- Numele si contul studentului --> |
<stud cont=''> </stud> |
<!-- Numele si contul coordonatorului --> |
<prof cont=''> </prof> |
<!-- Tema lucrarii de licenta --> |
<tema> </tema> |
<!-- Descrierea (optionala) a temei --> |
<desc> </desc> |
<!-- Legaturi (URI-uri) relevante --> |
<link> </link> |
</record> |
</database> |
PHP 4.0 include analizorul libxml elaborat de Daniel Veillard si integrat in motorul PHP de Uwe Steinman (vezi si capitolul referitor la DOM). PHP functioneaza cu libxml-2.0.0 sau o versiune superioara.
Arborele abstract asociat unui document XML va putea fi creat de una dintre functiile:
xmldoc() - va genera arborele pornind de la un sir de caractere reprezentand un document XML;
xmldocfile() - va incarca un document XML de pe disc si va construi arborele;
new_xmldoc() - va genera un arbore vid.
Arborele DOM va fi reprezentat in PHP printr-un obiect apartinand clasei speciale 'DOM document' avand proprietatile doc (resursa), version (sir de caractere, '1.0' in prezent) si type (intreg lung). Sunt puse la dispozitie urmatoarele metode:
root() - returneaza nodul radacina al arborelui DOM;
addroot() - adauga un nod radacina la un arbore vid creat de new_xmldoc()
dtd() - returneaza un obiect apartinand clasei DTD, care nu poseda metode, ci numai membrii-data name (numele elementului radacina al documentului XML), sysid (contine un identificator sistem al DTD-ului asociat documentului, e.g. impresii.dtd) si extid (reprezinta un identificator extern);
dumpmem() - converteste in sir de caractere reprezentarea interna a arborelui DOM.
Un script PHP care va genera documentul XML:
<?xml version='1.0' ?> |
<nume>Sabin-Corneliu Buraga</nume> |
va fi urmatorul:
// un nou arbore DOM |
$doc = new_xmldoc('1.0'); |
// insereaza nodul-radacina |
$root = $doc->add_root('nume'); |
// adauga nodului un continut |
$root->content = 'Sabin-Corneliu Buraga'; |
// afiseaza documentul XML generat |
print (htmlspecialchars($doc->dumpmem())); |
Dupa cum se poate remarca, putem foarte usor construi prin program documente sau fragmente de documente XML, ceea ce nu se putea cu expat
Dupa cum am vazut, in cadrul modelului DOM orice componenta a unui document XML va fi reprezentata prin intermediul unui nod al arborelui asociat. Un obiect de tip nod va avea metodele:
parent() - desemneaza nodul parinte al nodului curent;
children() - returneaza nodurile copii ale nodului curent;
attributes() - furnizeaza atributele asociate unui nod de tip element;
new_child() - genereaza un nod copil;
getattr() - returneaza valoarea unui atribut, daca exista;
setattr() - modifica valoarea unui atribut.
Sunt disponibile si urmatorii membri-data:
type - desemneaza tipul de nod; pentru o manevrare mai facila a tipurilor nodurilor sunt predefinite constantele de mai jos:
Constanta |
Valoare |
XML_ELEMENT_NODE | |
XML_ATTRIBUTE_NODE | |
XML_TEXT_NODE | |
XML_CDATA_SECTION_NODE | |
XML_ENTITY_REF_NODE | |
XML_ENTITY_NODE | |
XML_PI_NODE | |
XML_COMMENT_NODE | |
XML_DOCUMENT_NODE | |
XML_DOCUMENT_TYPE_NODE | |
XML_DOCUMENT_FRAG_NODE | |
XML_NOTATION_NODE |
Aceste constante se pot folosi si in programele C folosind biblioteca libxml
name - reprezinta numele nodului (e.g. numele unui element XML);
content - desemneaza continutul unui anumit nod (daca exista).
Pentru a parcurge intreg arborele de noduri sau numai parti din el ne putem folosi de xmltree(), functie care va analiza documentul XML dat ca parametru (sub forma de sir de caractere) si va returna o structura de obiecte PHP reprezentand acel document. Aceasta structura nu va putea fi insa modificata.
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 1399
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved