PHP OOP – Clase si Obiecte, Metoda constructor 13
OOP (Object Oriented Programming – Programare Orientata pe obiecte) este un concept (sau tehnica) de programare care trateaza datele si functiile ca obiecte. Important la acest concept este sa fie inteleasa bine diferenta dintre Clasa (Class) si Obiect (Object).
Inainte de a trece la lucruri practice, iata cate ceva teoretic despre OOP.
• Clasa este o structura de date compacta, care contine variabile (numite proprietati) si functii (numite metode) prin care se pot crea diferite instructiuni legate intre ele in acea structura.
• Obiectele sunt elementele din script create cu o clasa, si prin care se pot folosi proprietatile si metodele din acea clasa.
– De exemplu, pentru a intelege mai bine, prin analogie, o Clasa poate fi asemanata cu planul /schita unei case, iar obiectul este insasi casa, si contine proprietatile (culoare, ferestre, etc.) definite in schita. Precum, folosind acelasi plan se pot construi mai multe case, asa si in OOP, folosind aceeasi clasa se pot crea unul sau mai multe obiecte prin care se aplica in script proprietatile si functiile definite in clasa.
Practic, o clasa este o „fabrica” de obiecte, prin care se creaza obiecte cu aceeasi structura, avand proprietati si metode identice. Fiecare astfel de obiect creat poarta denumirea de Instanta a clasei.
• In OOP (Programarea Orientata pe Obiect) apar termenii: „Encapsulation” (Encapsulare), „Inheritance” (Mostenire) si „Polymorphism” (polimorfism.).
– Encapsularea reprezinta faptul de a utiliza proprietatile si metodele clasei fara a fi necesara cunoasterea sructurii ei. Astfel, cine foloseste o clasa intr-un script nu are nevoie sa cunoasca structura codului si instructiunilor din ea.
– Mostenirea e abilitatea unei clase de a folosi proprietati si functii definite in alta clasa din care este extinsa (denumita parinte).
– Polimorfismul e abilitatea unei clase de a face mai multe lucruri, diferite, sau de a utiliza o clasa sau alta pentru a realiza lucrul dorit, avand functii similare. De exemplu, o rigla poate fi utilizata pentru a trasa linii dar si pt. a masura ceva, iar pentru a trasa linii se poate folosi si alta rigla dreapta. Acesta e polimorfism.
Pentru cine este obijnuit cu modul de creare a claselor in PHP 4, incepand de la versiunea PHP 5 sunt unele schimbari de sintaxa:
– Proprietatile nu se mai declara cu var
– Metoda Constructor se defineste cu numele __construct
1. Creare clasa
Definirea unei clase incepe cu un cuvantul cheie „class„, urmat de numele clasei si corpul ei (cuprins intre acolade). In corpul clasei se definesc proprietatile si metodele ei.
– Proprietatile sunt variabile definite in interiorul clasei.
– Metodele sunt functii create in interiorul clasei.
Structura general de alcatuire a unei clase este urmatoarea:
- class nume_clasa {
$proprietate;
function metoda() {
// Codul functiei
}
}
Pentru a construi o clasa profesionala, cu elemente incluse in PHP 5+, sunt necesare si alte lucruri care trebuie adaugate.
– La definirea unei clasei si a elementelor din ea (proprietati, metode) se pot aplica unele atribute speciale prin care se defineste domeniul lor de lucru (de existenta). Acest atribut se adauga inaintea variabilei sau a cuvantului functions, si poate fi unul din cuvintele:
- public – valabil in tot scriptul
- private – valabil doar in interiorul acelei clase
- protected – valabil doar in acea clasa si sub-clasele extinse din ea
– Daca nu e adaugat nici un atribut, se considera „public”.
Astfel, formula completa pentru crearea unei clase este:
- class Nume_Clasa {
atribut $proprietate1;
atribut $proprietate2;
……………..
atribut function metoda1() {
// Codul functiei
}
atribut function metoda2() {
// Codul functiei
}
……………..
}
– Pentru o mai buna organizare, este indicata crearea fiecarei clase intr-un fisier PHP separat si cu o denumire de forma „class.Nume_Clasa.php„. Acest lucru nu e obligatorriu, doar ca indicatie; clasa poate fi creata si in scriptul unde e folosita.
Iata un exemplu de clasa simpla, ce contine doua proprietati, prima cu atribut public (denumita $site), a doua private (denumita $categorie) si o metoda cu atribut public (cu numele „pagini”).
Exemplu SiteClas
<?php
// Se defineste clasa SiteClas
class SiteClas {
public $site = 'www.CursPHP.net/'; // Proprietatea publica
private $categorie = 'php-mysq/'; // Proprietate privata
// Creare metoda, preia un argument
public function pagini($pag) {
// Afiseaza adresa URL formata din valoarea celor 2 proprietati si argumentul primit
echo '<br />'. $this->site. $this->categorie. $pag;
}
}
?>
– Aceasta este clasa „SiteClas”, pentru a-o putea folosi in orice script, sa o salvam intr-un fisier separat, denumit „class.SiteClas.php„.
– Formula „$this->site” indica /face sa fie apelata proprietatea „site” a obiectului curent din aceasta clasa (termenul $this (acesta, aceasta) indica precis ca se face referire la proprietatea respectiva, din instanta curenta).
Cand se acceseaza proprietati se foloseste un singur caracter $. Sintaxa este $obj->proprietate, desi variabila e definita „$proprietate”.
2. Utilizare clasa
Dupa ce o clasa e creata, pentru a putea fi utilizata trebuie creata o instanta de obiect a clasei. Aceasta instanta se declara in scriptul PHP, cu formula:
$nume_obiect = new Nume_Clasa();
– „nume_obiect” este numele obiectului prin care pot fi utilizate proprietatile si metodele acelei clase.
Iata cum poate fi utilizata clasa „SiteClas” prezentata mai sus (pt. explicatii, studiati si comentariile din cod).
<?php
include('class.SiteClas.php'); // Include clasa
$objSite = new SiteClas(); // Creare instanta de obiect la clasa SiteClas
echo $objSite->site; // Afisaza valoarea proprietatii "site"
// Apeleaza metoda pagini() [cu un argument, dupa cum a fost definita]
$objSite->pagini('oop-clase-obiecte.html');
// Modifica valoarea proprietatii "site" si apeleaza iar metoda pagini()
$objSite->site = 'www.alt-site.net/';
$objSite->pagini('oop-clase-obiecte.html');
?>
– La include() trebuie adaugata calea si numele fisierului cu clasa, in raport cu scriptul curent (aici sunt in acelasi director).
– Inainte de a putea utiliza proprietati si metode din clasa, trebuie creata o instanta de obiect, deoarece prin aceasta se apeleaza aceste elemente, dupa sintaxa:
$obiect->element
– Prin apelarea metodei „pagini()” ( $objSite->pagini(‘oop-clase-obiecte.html’); ) se va executa codul functiei „pagini()” definita in clasa, care afiseaza intr-un sir o adresa URL compusa din valorile proprietatilor si argumentul primit.
– Observati ca valoarea proprietatilor poate fi modificata in cadrul scriptului. Proprietatea „site” poate fi apelata atat pentru a fi utilizata /afisata valoarea ei cat si pentru adaugarea altei valori (aici sirul ‘www.alt-site.net/’).
– In browser va afisa:
www.CursPHP.net/
www.CursPHP.net/php-mysq/oop-clase-obiecte.html
www.alt-site.net/php-mysq/oop-clase-obiecte.html
Daca se incearca apelarea proprietatii private (aici „categorie”), de ex.: echo $objSite->categorie; , va determina o eroare ca cea de jos. Aceasta proprietate fiind declarata private poate fi utilizata doar in codul din interiorul clasei.
Fatal error: Cannot access private property SiteClas::$categorie in E:\server\www\index.php on line 15
Valoarea data unei proprietati definita in clasa poate fi de orice tip: sir (string), numar, Array sau Object.
3. Metoda constructor
Metoda constructor e un tip special de functie din interiorul Clasei. Se declara cu numele __construct (doua caractere „_” in fata). Aceasta metoda este mereu „public” chiar daca nu se mentioneaza special atributul „public”. Diferenta fata de celelalte functii este aceea ca Metoda Constructor e apelata automat cand se creaza o instanta la clasa respectiva, codul din ea se executa in momentul cand e creat obiectul (cu new).
Iata o noua versiune a clasei „SiteClas”, care include si metoda constructor, plus o metoda cu atribut protected.
<?php
// Se defineste clasa SiteClas
class SiteClas {
public $site = 'www.CursPHP.net/'; // Proprietate publica
private $categorie = 'php-mysq/'; // Proprietate privata
// Definire metoda constructor
public function __construct($nume) {
// Afiseaza un mesaj de bun venit, incluzand proprietatea "site"
echo 'Bine ai venit '. $nume. ' pe '. $this->site. '<br />';
echo $this->Mesaj(); // adauga si ce returneaza metoda Mesaj()
}
// Metoda protected
protected function Mesaj() {
// Returneaza un mesaj cu proprietatea 'categorie'
return 'Categoria de cursuri '. $this->categorie;
}
// Creare metoda, preia un argument
public function pagini($pag) {
// Afiseaza adresa URL formata din valoarea celor 2 proprietati si argumentul primit
echo '<br />'. $this->site. $this->categorie. $pag;
}
}
?>
– Deoarece Metoda Constructor preia un parametri ($nume) [se pot adauga mai multi, ca la orice functie], cand se creaza o instanta la aceasta clasa trebuie sa fie adaugat si un argument.
<?php
include('class.SiteClas.php'); // Include clasa
// Creare instanta de obiect la clasa SiteClas, cu argumentul necesar
$objSite = new SiteClas('Marius');
?>
– Prin executia metodei „__construct()„, apelarea $this->Mesaj() determina si executia metodei Mesaj(), care avand atribut „protected” poate fi apelata doar in codul din corpul clasei sau alte clase extinse din ea (despre clase extinse intr-o lectie viitoare).
– Acest cod simplu va returna in fereastra urmatorul mesaj:
Bine ai venit Marius pe www.CursPHP.net/
Categoria de cursuri php-mysq/
– Fapt ce demonsreaza ca Metoda Constructor este apelata automat si se executa codul din ea cand e creata instanta de obiect.
Dupa cum se arata in exemplu de sus, in metoda constructor pot fi apelate si alte metode sau proprietati definite in clasa, cu sintaxa $this-> , fapt ce va face ca si acele metode sa fie executate cand e creat obiectul.
– Daca se apeleaza in script (in afara clasei) o metoda „protected” sau „private” (de ex., aici: $objSite->Mesaj();) va genera eroare.
• Daca metoda constructor e definita cu un anumit numar de parametri, fara valoare initiala, cand se creaza instanta de obiect, clasa trebuie sa fie apelata cu acelasi numar de argumente, altfel returneaza eroare.
De ex., metoda constructor din exemplu precedent e definita cu un parametru ($nume), daca s-ar crea o instanta fara argument, de forma: $obj = new SiteClass(), va genera o eroare de genul:
Missing argument 1 for SiteClas::__construct(), called in …
Dar se pot declara parametri cu valoare deja atribuita, astfel, argumentul pentru ei devine optional.
De ex., in clasa Test de mai jos, metoda constructor e definita cu parametru $nume=’Tu’.
<?php
class Test {
// Constructor (cu un parametru cu valoare predefinita)
public function __construct($nume='Tu') {
echo '<br />Salut '. $nume;
}
}
?>
– Daca instanta e creata fara argument, metoda constructor va folosi parametru $nume cu valoarea lui prestabilita („Tu„), iar cand e adaugat argument, preia valoarea acestuia; dupa cum arata rezultatul afisat de scriptul urmator, in care se creaza doua instante de obiect la clasa Test.
<?php
// Creare instanta de obiect la clasa Test, fara argument
$obj1 = new Test();
// A doua instanta de obiect la clasa Test, cu argument
$obj2 = new Test('Marius');
?>
– Acest exemplu arata si faptul ca se pot crea si folosi mai multe instante de obiect la aceeasi clasa.
– In browser apare:
Salut Tu
Salut Marius
In lectia urmatoare sunt prezentate metodele accesor si _destruct().
PHP OOP – metode Accesor si Destructor
1. Metoda Accesor
Variabilele (proprietatile) create intr-o clasa pot avea de la inceput o valoare sau pot fi doar simplu declarate, urmand ca valoarea lor sa fie atribuita prin intermediul unei functii (metode). Aceasta functie e denumita generic Metoda Accessor, e la fel ca oricare alta metoda, doar ca scopul ei este de a atribui valori proprietatilor; in rest, se construieste si se apeleaza la fel ca celelalte.
Ca sa vedeti cum functioneaza „metoda accessor„, incercati urmatorul exemplu, in care este creata o clasa „SiteClas” cu doua proprietati (‘site’ si ‘categorie’), ambele fara valoare, iar metoda Constructor e folosita si ca accesor, atribuie valori proprietatilor prin parametri ei.
<?php
// Se defineste clasa SiteClas
class SiteClas {
public $site; // Proprietate declarata fara valoare
private $categorie; // Proprietate privata, fara valoare
// Constructor
public function __construct($site, $categorie) {
// Atribuie proprietatilor valoarea din parametri
$this->site = $site;
$this->categorie = $categorie;
}
// Metoda pt. afisare adresa pagini
public function pagini($pag) {
// Afiseaza un sir cu adresa URL, www., valoarea celor 2 proprietati si argumentul primit
echo '<br />www.'. $this->site.'/'. $this->categorie.'/'. $pag;
}
}
?>
– Cand e creata instanta de obiect la clasa, metoda constructor (care se executa automat) atribuie proprietatilor „site” si „categorie” valorile din parametri, care trebuie adaugate la crearea instantei.
– Metoda pagini(), cand e apelata, afiseaza o adresa URL formata din valoarea proprietatilor „site„, „categorie” (atribuite prin constructor) si argumentul ei $pag.
– Salvam clasa intr-un fisier denumit „class.SiteClass.php„, iar pentru test, se adauga urmatorul cod intr-un fisier .php salvat in acelasi director unde e si clasa.
<?php
include('class.SiteClas.php'); // Include clasa
// Creare instanta de obiect la clasa SiteClas, cu argumentele necesare
$objSite = new SiteClas('CursPHP.net', 'php-mysql');
$objSite->pagini('oop-clase-obiecte.html'); // Apelare metoda pagini()
?>
– Dupa executie, in browser va afisa:
www.CursPHP.net/php-mysql/oop-clase-obiecte.html
Valoarea proprietatii „site„, avand atribut „public”, poate fi modificata si pe parcurs in script, cu expresia:
$objSite->site = valoare;
2. Accesare si modificare proprietati prin metode Accesor
Variabilele in PHP nu au un tip de date stabilit precis la declararea lor, de exemplu, o variabila poate sa contina initial ca valoare un numar, iar pe parcursul scriptului sa i-se atribuie ca valoare un sir sau un Array. Aceasta flexibilitate este folositoare, dar in unele situatii poate prezenta probleme in anumite contexte din codul unei metode.
De exemplu, daca intr-o metoda se parcurg datele dintr-o proprietate de tip Array iar in script acea proprietate primeste o valoare de tip Sir, apar erori.
Pentru a fi siguri ca o proprietate primeste doar tipul de date care poate fi corect utilizat, se declara ca private si se folosesc metode accesor pentru accesarea ei, cu functii PHP de verificare a tipului de date. Aceste functii sunt:
- is_bool() – Boolean – una din valorile speciale: true sau false
- is_integer() sau is_int() – Integer – numere intregi (fara virgula)
- is_float() sau is_double() – Float /Double – numere cu zecimale (cu virgula)
- is_numeric() – Number – orice numar sau sir ce reprezinta un numar
- is_string() – String – siruri de caractere si cuvinte
- is_array() – Array – Array
- is_object() – Object – Obiect
- is_resource() – Resource – un identificator pentru lucru cu date din sure externe (fisier, baza de date)
- is_null() – Null – Valoare NULL sau nedefinita
Iata o alta versiune a clasei TestClas. Ambele proprietati sunt declarate „private”, ca sa nu fie modificate in mod direct in afara clasei. Valorile initiale le primesc la crearea instantei (prin constructor). Pentru a putea accesa si modifica proprietatea „categorie” in script, se creaza special cate o metoda accesor: getCategorie() si setCategorie() (vedeti si explicatiile din cod).
<?php
// Se defineste clasa SiteClas
class SiteClas {
// Definire proprietati private, fara valoare
private $site;
private $categorie;
// Constructor
public function __construct($site, $categorie) {
// Atribuie proprietatilor valoarea din parametri
$this->site = $site;
$this->categorie = $categorie;
}
// Metoda accesor - returneaza valoarea proprietatii 'categorie'
public function getCategorie() {
return $this->categorie;
}
// Metoda accesor pt. setare valoare la "categorie"
public function setCategorie($val) {
// Daca $val e de tip Sir (string) si are cel putin un caracter
// Atribuie valoarea lui proprietatii 'categorie'
// Altfel, returneaza eroare
if(is_string($val) && strlen($val)>0) {
$this->categorie = $val;
}
else throw new Exception('Valoare incorecta pt. categorie');
}
// Metoda pt. afisare adresa pagini
public function pagini($pag) {
// Afiseaza un sir cu adresa URL, www., valoarea celor 2 proprietati si argumentul primit
echo '<br />www.'. $this->site.'/'. $this->categorie.'/'. $pag;
}
}
?>
– Prin declararea proprietatilor ca „private„, se respinge accesul direct la ele in afara clasei, iar pt. proprietatea „categorie” s-a creat posibilitatea de a fi accesata si modificata valoarea ei prin metodele accesor: getCategorie() si setcategorie($val).
– In setCategorie($val) se atribuie valoarea transmisa pt. $val la „categorie” (prin formula $this->categorie = $val;) doar daca $val e de tip Sir (String) si are cel putin un caracter; altfel, utilizand formula speciala „throw new Exception(‘Eroare’)” returneaza un mesaj de eroare.
– Pentru a testa efectul acestor metode, se executa scriptul urmator, in care e utilizata o instanta la aceasta clasa.
<?php
include('class.SiteClas.php'); // Include clasa
// Creare instanta de obiect la clasa SiteClas
$objSite = new SiteClas('CursPHP.net', 'php-mysql');
// Afiseaza valoarea returnata de getCategorie() (reprezentand valoarea proprietatii "categorie")
echo $objSite->getCategorie();
// Modifica prin setCategorie() valoarea proprietatii "categorie"
$objSite->setCategorie('html');
$objSite->pagini('introducere.html'); // Apelare metoda pagini()
?>
– In browser scriptul va afisa:
php-mysql
www.CursPHP.net/html/introducere.html
– „php-mysql” este valoarea initiala data proprietatii „categorie” prin crearea instantei la clasa. Dar prin modificarea ei cu $objSite->setCategorie(‘html’);, metoda pagini() va utiliza proprietatea „categorie” cu aceasta valoare (html).
3. Metoda Destructor
Metoda Destructor se creaza cu numele __destruct (doua caractere ‘_’ la inceput). Aceasta metoda este opusul lui __construct. Daca metoda constructor e apelata automat cand se creaza o instanta de obiect la clasa, metoda Destructor se apeleaza automat cand e stearsa, cu unset(), instanta la acea clasa.
Se intelege mai bine din urmatorul exemplu. Clasa Test de mai jos contine o proprietate privata, „nume”, o metoda accesor „setNume()”, metoda constructor si destructor.
<?php
// Clasa Test
class Test {
private $nume;
// Constructor
public function __construct($nume) {
// Atribuie proprietatii 'nume' valoarea din parametru
// si afiseaza un mesaj
$this->nume = $nume;
echo 'Bine ai venit '. $this->nume. '<br />';
}
// Metoda accesor - schimba valoarea proprietatii 'nume'
public function setNume($nume) {
$this->nume = $nume;
}
// Metoda Destructor
function __destruct() {
echo 'Cu bine '. $this->nume;
}
}
?>
– Ca sa testam efectul metodei __destruct, se foloseste urmatorul script (vedeti explicatiile din cod).
<?php
// Creare instanta de obiect la clasa Test
$obj = new Test('Mar');
// Apeleaza metoda setNume(), care seteaza alta valoarea la prop. 'nume'
$obj->setNume('Plo');
// Sterge instanta de obiect $obj
unset($obj);
?>
– Prin argumentul ‘Mar’ adaugat la crearea instantei, metoda constructor atribuie aceasta valoare proprietatii „nume”, pe care o afiseaza in mesajul returnat.
– Apelarea metodei setNume() modifica valoarea acestei proprietati, iar cand instanta de obiect e stearsa, cu unset($obj), se autoapeleaza metoda „__destruct” si determina executia codului din ea, care va afisa alt mesaj, cu proprietatea „nume” avand ultima valoare setata.
– Rezultatul afisat in browser este:
Bine ai venit Mar
Cu bine Plo
Metoda destructor este utila cand se doreste executarea automata a unor ultime instructiuni cand instanta la clasa e stearsa din memorie prin apelarea functiei PHP unset().
In lectia urmatoare sunt prezentate Constante si elemente Statice in Clasele PHP.
OOP – Constante, Proprietati si Metode Statice
1. Constante
Pe langa proprietati (variabile) si metode (functii), in corpul clasei pot fi definite si constante, prin cuvantul const. Sintaxa generala este:
const NUME_CONSTANTA;
– Diferenta principala dintre constante si proprietati e faptul ca valoarea constantei ramane aceeasi, nu mai poate fi modificata.
– La constante nu se foloseste atribut (public, private, protected), doar cuvantul const, ele sunt recunoscute ca publice.
– Constantele se acceseaza prin numele clasei si operatorul doua-puncte (::) (atat in interiorul clasei cat si in script unde e creata instanta), cu formula:
Nume_Clasa::NUME_CONSTANTA
Pentru a se distinge mai clar proprietatile de constante, se obisnueste ca numele constantelor sa fie scris cu majuscule.
Iata un exemplu de clasa cu o constanta, si cum poate fi aceasta utilizata. Clasa Test de mai jos contine o proprietate „raza”, o constanta „PI”, metoda constructor si o metoda „getArea()”.
<?php
// Clasa Test
class Test {
public $raza; // Proprietate
const PI = 3.14; // Constanta
// Constructor
public function __construct($raza) {
// Daca $raza e un numar, atribuie valoarea la proprietatea "raza"
// Altfel, seteaza un mesaj de eroare
if(is_numeric($raza)) $this->raza = $raza;
else throw new Exception('Valoare incorecta pt. raza');
}
// Returneaza aria cercului
public function getArea() {
return Test::PI * pow($this->raza, 2);
}
}
?>
– Metoda constructor verifica daca argumentul adaugat la crearea instantei este de tip numar, in caz Adevarat, atribuie acea valoare la proprietatea „raza”. Altfel, returneaza eroarea definita in Exception().
– Metoda getArea() returneaza aria cercului (formula matematica este PI*Raza2).
– Pentru a testa aceasta clasa si modul de accesare a constantei, folosim urmatorul script.
<?php
echo Test::PI; // Afiseaza valoarea constantei PI din clasa Test
// Creare Instanta la clasa Test
$objTest = new Test(78);
// Afiseaza aria cercului cu raza 78, returnata de metoda getArea()
echo '<br /> Aria = '. $objTest->getArea();
?>
– Observati cum e accesata constanta „PI”, cu aceeasi formula in interiorul clasei si in script, inainte de a crea instanta la clasa. Astfel, constantele pot fi accesate si fara a crea o instanta de obiect la acea clasa.
– Rezultatul afisat de acest exemplu este:
3.14
Aria = 19103.76
Daca se incearca modificarea valorii constantei, in clasa sau in afara ei (Clasa::CONSTANTA=alta_valoare;), va genera eroare.
– In interiorul clasei, constantele pot fi accesate si prin cuvantul special self in loc de numele clasei:
self::CONSTANTA
– In afara clasei, constantele pot fi accesate si prin intermediul instantei de obiect, dar dupa crearea ei. In exemplu de mai sus, dupa declararea instantei se poate folosi si $objTest::PI;
2. Proprietati si metode Statice
Pe langa atributele: „public”, „private” si „protected”; prin care se defineste domeniul de acces al proprietatilor si metodelor; acestea pot fi create si ca statice, astfel, vor apartine exclusiv clasei, si nu pot fi apelate prin instanta de obiect a clasei, ci direct prin ea, cu operatorul doua-puncte (::).
Pentru a defini o proprietate sau metoda ca statica, se foloseste cuvantul static inaintea atributului, cand sunt create aceste elemente. Sintaxa generala este:
static atribut $proprietate
static atribut function Metoda()
– atribut este unul din cuvintele: public, private sau protected; care stabilesc domeniul de existenta.
Aceste elemente statice nu pot fi apelate prin instanta de obiect deoarece nu apartin ei, ele apartin clasei si pot fi apelate cu formula:
NumeClasa::$proprietate
NumeClasa::metoda()
– Observati ca la proprietate, cand e statica trebuie adaugat si caracterul $ (fara caracterul ‘$’, sintaxa „NumeClasa::proprietate” este confundata cu cea pt. constante).
• In interiorul clasei, elementele statice pot fi apelate si prin cuvantul special self in loc de numele clasei:
self::$proprietate sau self::Metoda()
Iata un exemplu din care se intelege mai bine. In clasa urmatoare, denumita „elStatic” se definesc doua proprietati statice: una cu atribut „private” (site), a doua publica (id); o metoda constructor si alta statica.
<?php
// Clasa elStatic
class elStatic {
// Definire proprietati statice
static private $site = 'www.CursPHP.net'; // Privata
static public $id = 78; // Publica
// Constructor
public function __construct($site) {
// Daca parametru $site e de tip String si cel putin 4 caractere
// Atribuie valoarea la proprietatea "site" si apeleaza metoda getProp()
// Altfel, seteaza un mesaj de eroare
if(is_string($site) && strlen($site)>3) {
elStatic::$site = $site;
self::getProp(); // Apelare prin cuvantul special self
}
else throw new Exception('Valoare incorecta pt. site');
}
// Metoda statica
static public function getProp() {
// Afiseaza valoarea proprietatilor statice (folosind numele clasei, dar si cuvantul self )
echo '<br /> ID = '. elStatic::$id. ' - site: '. self::$site;
}
}
?>
– Vedeti explicatiile din cod si modul de lucru, cum sunt accesate proprietatile si metoda statica.
– Deoarece elementele statice apartin direct clasei, pentru utilizarea lor nu e nevoie de crearea unei instante la aceasta clasa. Dar se pot folosi si instante, acestea determina auto-apelarea metodei constructor, dupa cum puteti vedea in scriptul urmator, care foloseste elemente din clasa „elStatic” si o instanta la ea.
<?php
echo elStatic::$id; // Afiseaza valoarea proprietatii statice "id"
elStatic::getProp(); // Apeleaza metoda statica getProp()
elStatic::$id = 89; // Modifica valoarea proprietatii statice "id"
// Creare Instanta la clasa elStatic
$obj = new elStatic('www.php.net');
?>
– Observati ca valoarea proprietatii statice care e publica (aici „id”) poate fi schimbata in afara clasei si influenteaza dupa ea toate instructiunile in care e folosita (ca si cum ar fi modificata in clasa), inclusiv orice instanta la clasa, creata dupa modificare.
– Acest exemplu va afisa in browser urmatorul rezultat:
78
ID = 78 – site: www.CursPHP.net
ID = 89 – site: www.php.net
– Prin crearea instantei s-a obtinut rezultatul dat de metoda constructor.
• Intr-o clasa se pot folosi combinate: constante, metode si proprietati statice si generale (fara „static”), dar in corpul metodelor statice se pot utiliza doar elemente care si ele sunt statice, sau constante. Accesarea in codul dintr-o metoda statica a unei proprietati cu formula $this->proprietate genereaza eroare.
$this face referire la instanta de obiect curenta, self se refera la clasa curenta.
• La pagina Functii – clase si obiecte sunt prezentate cateva functii PHP pentru Clase si Obiecte.
In lectia urmatoare e prezentata utilizarea mostenirii si clasele extinse.
PHP OOP – Clase extinse si Mostenire
Mostenirea este unul din cele mai utile instrumente ale Programarii Orientate pe Obiect – OOP.
Prin mostenire se intelege transmiterea proprietatilor, constanttelor si a functiilor de la o clasa la alta, intr-o structura ierarhica. Prima clasa este clasa de baza, denumita „parinte„, legata de aceasta se poate crea o sub-clasa, denumita „copil„; sub-clasa ‘copil’ mosteneste proprietatile si metodele clasei ‘parinte’ (cele care sunt cu atribut „public” sau „protected”), le poate folosi in instructiunile din propriul cod si le transmite cand se creaza o instanta de obiect la ea. Precum in natura copii mostenesc genele parintilor.
1. Creare clasa copil
Sub-clasa „copil” se creaza cu formula:
class ClasaCopil extends ClasaParinte
Iata cum se aplica acest procedeu in programarea PHP OOP.
In exemplu prezentat aici se construieste intai o clasa de baza, denumita Site, cu doua proprietati: una cu atribut private (site), alta cu atribut public (categorie), constructor si o metoda getPag().
<?php
// Clasa Site
class Site {
// Definire proprietati, private si public
private $site;
public $categorie = 'php-mysql';
// Constructor
public function __construct($site) {
// Daca parametru $site e un Sir cu cel putin 5 caractere, atribuie valoarea la proprietatea "site"
// Altfel, seteaza un mesaj de eroare
if(is_string($site) && strlen($site)>4) $this->site = $site;
else throw new Exception('Valoare incorecta pt. site');
}
// Metoda getPag()
public function getPag($pag) {
// Defineste si returneaza adresa URL a paginii
$url = $this->site. '/'. $this->categorie. '/'. $pag;
return $url;
}
}
?>
– Metoda Constructor atribuie valoarea din parametru $site la proprietatea „site”.
– Metoda getPag() returneaza o adresa URL formata din proprietatile clasei si parametru ei.
Salvam aceasta clasa intr-un fisier „class.Site.php„.
• Aceasta clasa poate fi utilizata pentru afisarea unui sir cu o adresa URL, prin apelarea metodei getPag(). Daca vrem sa obtinem aceasta adresa intr-un tag HTML tip link (<a>) se poate crea o noua metoda, pentru alta facilitate alta metoda, si tot asa se aglomereaza codul clasei, fapt ce devine o problema in cazul unor clase mari. O alta varianta este crearea unei sub-clase extinse din aceasta. Sub-clasa (copil) are abilitatea de a mosteni /utiliza toate proprietatile si metodele definite ca publice si protected in clasa de baza (parinte) ca si cum ar fi create in ea (fara sa mai fie scrise inca o data). Astfel, in clasa copil se creaza doar instructiunile cu noua functie pe care o dorim, si nici nu mai trebuie modificata clasa parinte.
In continuarea acestui exemplu se creaza o alta clasa, denumita LinkSite, ca extindere a clasei Site. Ea contine doar o metoda getLink() pentru afisarea unui link.
<?php
include('class.Site.php'); // Include clasa parinte (Site)
// Creare clasa copil LinkSite, extinsa din Site
class LinkSite extends Site {
// Metoda getLink()
public function getLink($pag) {
// Afiseaza un link format din getPag() si "categorie" din clasa parinte
echo '<a href="http://'. $this->getPag($pag). '" title="'. $this->categorie. '">Link</a><br />';
}
}
?>
Salvam aceasta clasa, cu denumirea „class.LinkSite.php” in acelasi director unde e salvata si clasa Site.
Acum, atentie la explicatii:
– Pentru a avea acces la definitiile din clasa principala Site, deoarece se afla intr-un fisier extern, o includem cu include().
– Cuvantul special „extends” stabileste identitatea clasei LinkSite ca fiind o extindere a clasei Site.
– In metoda getLink() se folosesc proprietatea „categorie” si metoda „getPag()” din clasa parinte ca si cum ar fi fost definite in aceasta clasa.
Aceste elemente pot fi accesate in clasa copil deoarece au atribut „public” (functioneaza si cu „protected”). Dar proprietatea „site”, care are atribut „private” in clasa parinte, nu poate fi accesata in cea copil.
– Desi aceasta clasa nu are o metoda constructor, ea mosteneste constructorul clasei parinte, astfel, cand se creaza o instanta de obiect la clasa LinkSite trebuie adaugat si un argument de tip Sir, deoarece asa e definita metoda „__construct($site)” in clasa de baza (Site).
Sa testam aceasta clasa copil, cu scriptul urmator.
<?php
include('class.LinkSite.php'); // Include fisierul cu subclasa LinkSite
// Creare instanta la clasa copil LinkSite
$objLink = new LinkSite('www.CursPHP.net');
// Apeleaza metoda getLink() (definita in clasa copil);
$objLink->getLink('oop-clase-extinse-mostenire.html');
// Modifica valoarea proprietatii "categorie" (aflata in clasa parinte)
$objLink->categorie = 'ajax';
// Afiseaza rezultatul dat de metoda getPag() (creata in clasa parinte)
echo $objLink->getPag('introducere.html');
?>
– Deoarece clasa LinkSite se afla intr-un fisier PHP extern, o includem cu include().
– La crearea instantei de obiect se adauga si argumentul necesar, un sir (‘www.CursPHP.net‘), cerut de metoda constructor a clasei de baza, care e si ea mostenita.
– Observati cum sunt accesate proprietatea „categorie” si metoda „getPag()” (care se afla in clasa parinte), prin instanta de obiect la clasa copil (LinkSite) ca si cum ar fi create in ea. Acesta este efectul mostenirii, atat de util in OOP.
In browser va afisa urmatorul rezultat:
Link
www.CursPHP.net/ajax/introducere.html
2. Redefinire metode
In exemplu de mai sus, clasa copil LinkSite a mostenit si metoda „__construct()” din clasa parinte Site, fapt ce determina executarea codului din acel Constructor si cand e creata instanta la clasa copil. Uneori aceasta functie nu e adecvata in sub-clasa. Pentru a evita acest lucru, metodele inadecvate pot fi rescrise prin adaugarea uneia cu acelasi nume in clasa copil, astfel, la crearea instantei, va fi utilizata metoda, cu acelasi nume, din clasa copil.
– Rescrierea unei metode nu afecteaza cu nimic pe cea originala, modificarile efectuate sunt valabile doar in clasa copil in care se face rescrierea, respectiv, in alte sub-clase ale ei.
Iata o alta sub-clasa (PagSite) extinsa din Site. Aici se adauga si o metoda „__construct()” care o va anula pe cea din clasa parinte, se rescrie si metoda getPag().
<?php
include('class.Site.php'); // Include clasa parinte (Site)
// Creare clasa copil PagSite, extinsa din Site
class PagSite extends Site {
public $domeniu = 'CursPHP.net'; // Proprietate
// Constructor, rescrie pe cel din parinte (Site)
function __construct() {
// Fara instructiuni, executa nimic
}
// Metoda getPag(), rescrisa
public function getPag($pag) {
// Preia functionalitatea metodei getPag() din clasa parinte
$url = parent::getPag($pag);
// ... alte instructiuni pt. metoda getPag()
// Adauga in $url si valoarea proprietatii "domeniu"
$url = $this->domeniu. $url;
return 'Pagina: '. $url;
}
}
?>
– Prin crearea in aceasta sub-clasa a metodei „__construct()” se anuleaza efectul celei din clasa parinte, si neavand parametru, nici la creare instantei nu se mai adauga vreun argument.
– Pentru a pastra si functionalitatea initiala (din clasa parinte) a metodei rescrise, in corpul functie care face rescrierea, se adauga cu formula parent::nume_metoda() (tehnica folosita si in exemplu de sus, la getPag()).
In scriptul urmator se foloseste aceasta a doua sub-clasa.
<?php
include('class.PagSite.php'); // Include fisierul cu aub-clasa PagSite
// Creare instanta la clasa copil PagSite
$objPag = new PagSite();
// Modifica valoarea proprietatii "categorie" (aflata in clasa parinte)
$objPag->categorie = 'html';
// Afiseaza rezultatul dat de metoda getPag() (rescrisa)
echo $objPag->getPag('introducere.html');
?>
– Instructiunea $objPag->getPag(‘introducere.html’) apeleaza metoda „getPag()” din clasa la care s-a creat instanta de obiect (PagSite) deoarece exista cu aceasta denumire in ea. Se observa si din rezultatul afisat:
Pagina: CursPHP.net/html/introducere.html
3. Metode finale
In exemplu prezentat mai sus se vede cum o metoda din clasa de baza poate fi rescrisa in sub-clasa copil, dandu-i alta functionalitate. Sunt situatii in care nu se doreste ca o metoda sa poata fi rescrisa, in acest caz, prin adaugarea cuvantului final la inceputul declararii metodei se blocheaaaza posibilitatea rescrierii ei.
– De exemplu:
<?php
// Clasa Baza
class Baza {
// Metoda final
final public function numeMet() {
// Instructiunile functiei
}
}
// Definire clasa-copil din Baza
class CopilBaza extends Baza {
// Rescriere metoda numeMet()
public function numeMet() {
// Alte Instructiuni
}
}
?>
– Va genera eroarea:
Fatal error: Cannot override final method Baza::numeMet() in …
– Deoarece metoda „numeMet()” este declarata cu atribut „final”.
4. Clase finale
Precum metodele declarate cu „final” nu mai pot fi modificate in sub-clasa copil, asa se pot crea si clase care sa ramana fixe, fara sa se poata crea din ele alta sub-clasa. Acest lucru se obtine prin adaugarea cuvantului final inainte de class.
– De exemplu:
<?php
// Clasa Baza
final class Baza {
// ... Instructiuni
}
// Definire clasa-copil din Baza
class CopilBaza extends Baza {
// ... Alte Instructiuni
}
?>
– Va genera eroarea:
Fatal error: Class CopilBaza may not inherit from final class (Baza) in …
Metode magice __get, __set, __call, __toString
In Programarea Orientata pe Obiecte (OOP) din PHP exista cateva metode mai speciale, care incep cu „__” (doua caractere ‘_’), precum __construct(). Acestea sunt numite generic Metode Magice (Magic Methods) si se executa automat in situatii mai speciale, cum ar fi de exemplu __get() pentru accesari de proprietati inexistente.
In aceasta lectie sunt prezentate cateva din cele mai folosite astfel de metode: __get(), __set(), __call() si __toString().
– Toate aceste metode magice trebuie sa fie definite cu atribut public.
1. Metode __get si __set
Metodele magice: __get() si __set() se folosesc de obicei impreuna si sunt create pentru lucru cu proprietati care nu sunt definite.
- __get($name) – E apelata automat cand se acceseaza o proprietate care nu exista. Preia numele ei in parametru $name.
- __set($name, $value) – Se apeleaza automat cand se atribuie o valoare unei proprietati care nu exista. Preia numele ei in parametru $name si valoarea in parametru $value.
Iata un exemplu din care se intelege mai bine rolul lor. O clasa in care sunt folosite aceste metode, se creaza o instanta de obiect la ea apoi e accesata o proprietate inexistenta.
<?php
// Definire clasa AClas
class AClas {
// Proprietate care va retine valori atribuite unor proprietati nedeclarate
public $prop = array();
// Metoda magica __get() (pt. accesari proprietati nedefinite)
public function __get($name) {
// Daca exista element cu cheia '$name' in $prop, afiseaza valoarea lui
// Altfel, mesaj ca proprietatea nu exista
if(array_key_exists($name, $this->prop)) echo $this->prop[$name]. '<br />';
else echo 'Proprietatea <b>'. $name. '</b> nu exista.<br />';
}
// Metoda magica __set() (pt. cand se atribuie valori unor proprietati nedefinite)
public function __set($name, $value) {
// Adauga in $prop element cu cheia $name si valoarea value
$this->prop[$name] = $value;
echo 'Proprietatea <b>'. $name. '</b> nu exista. S-a atribuit valoarea <i>'. $value. "</i> la proprietatea: <b>prop['$name']</b><br />";
}
}
// Creare instanta de obiect la clasa AClas
$obj = new AClas();
// Apelare proprietate neexistenta
$obj->noprop; // Va determina executia metodei __get()
// Atribuire valoare la proprietate inexistenta
$obj->noprop = 'Valoare pt. noprop - PHP OOP'; // Va determina executia metodei __set()
// Apelare din nou a aceleiasi proprietati neexistente
$obj->noprop; // Va determina executia metodei __get()
// Se verifica direct si elementul pe care-l creaza __set()
echo 'Verificare: '. $obj->prop['noprop'];
?>
– $prop e definita ca tip Array ca sa stocheze, prin metoda __set(), valorile atribuite unor proprietati nedefinite.
– Cand prin instanta de obiect la clasa e accesata o proprietate care nu exista ($obj->noprop;), se executa automat metoda __get(). Aici e definita sa verifice in $prop daca are element cu cheia $name (numele proprietatii accesate), daca exista acel element, afiseaza valoarea lui, altfel, afiseaza un mesaj.
– Cand se atribuie o valoare la proprietatea nedefinita ($obj->noprop = ‘…’;), se executa automat metoda __set(). Aici e definita sa adauge in $prop un element cu numele proprietatii (cheie) si valoarea transmisa.
• Vedeti si explicatiile din cod.
– Acest script va afisa urmatorul rezultat:
Proprietatea noprop nu exista.
Proprietatea noprop nu exista. S-a atribuit valoarea Valoare pt. noprop – PHP OOP la proprietatea: prop[‘noprop’]
Valoare pt. noprop – PHP OOP
Verificare: Valoare pt. noprop – PHP OOP
2. Metoda __call
Metoda magica __call() e creata pentru cazuri cand sunt apelate metode inexistente. Sintaxa ei este:
__call($nume, $array_argumente)
– $nume reprezinta numele metodei apelate
– in $array_argumente sunt retinute intr-un Array argumentele adaugate la apelarea metodei.
In urmatorul exemplu e definita o astfel de metoda „__call()” care afiseaza un mesaj cu numele metodei inexistente care a fost apelata si argumentele transmise.
<?php
// Definire clasa AClas
class AClas {
// Metoda magica __call() (pt. apelari metode nedefinite)
public function __call($name, $args) {
// Afiseaza un mesaj cu numele metodei apelate si argumentele transmise
echo 'Metoda <b>'. $name. '</b> nu exista. Argumente: <i>'. implode(', ', $args). '</i>';
}
}
// Creare instanta de obiect la clasa AClas
$obj = new AClas();
// Apelare metoda inexistenta
$obj->site('cursuri', 'tutoriale'); // Va determina executia metodei __call()
?>
– In browser va afisa:
Metoda site nu exista. Argumente: cursuri, tutoriale
Incepand cu PHP 3.0 e adaugata o metoda similara, __callStatic(), aceasta se executa automat cand e apelata o metoda statica nedeclarata, prin formula: NumeClasa::metodaStatica()
3. Metoda __toString
Cu metoda __toString() se determina modul de reactie a clasei cand instanta de obiect la ea este folosita ca o variabila de tip sir (String), de exemplu cu „echo”.
In urmatorul exemplu e definita o clasa cu o metoda __construct() si una „__toString()” care afiseaza valoarea unei proprietati „mesaj”.
<?php
// Definire clasa AClas
class AClas {
private $mesaj; // Proprietate
// Metoda Constructor
public function __construct($mesaj) {
// Atribuie valoarea din parametru la proprietatea "mesaj"
$this->mesaj = $mesaj;
}
// Metoda magica __toString()
public function __toString() {
return $this->mesaj; // Returneaza valoarea proprietatii "mesaj"
}
}
// Creare instanta de obiect la clasa AClas
$obj = new AClas('Fii bine primit');
// Apelare instanta, ca pe o variabila de tip String
echo $obj; // Va determina executia metodei __toString()
?>
– In browser va afisa:
Fii bine primit
– Fara metoda __toString() adaugata in clasa, accesarea instantei de obiect simpla, cu „echo” sau „print” genereaza o eroare de genul:
Catchable fatal error: Object of class AClas could not be converted to string in …
• Mai sunt si alte metode magice, mai putin folosite, cum ar fi: __isset (se apeleaza cand e verificata cu „isset()” o proprietate inexistenta), __invoke (se executa cand instanta de obiect e apelata ca o functie), si altele; le puteti gasi la pagina oficiala PHP.net Metode Magice
OOP – Clase abstract si interface
Abstract si Interface (interfata) sunt tipuri de clase mai speciale in OOP, pentru lucru mai avansat in programarea orientata pe obiecte.
1. Clase si Metode abstract
Clasele abstracte se declara folosind cuvantul abstract inaintea lui „class”.
La aceste tipuri de clase nu se poate crea instanta de obiect, ele pot fi doar mostenite de alte clase extinse din ele.
In clasele abstracte se definesc si metode abstracte, acestea se declara cu acelasi cuvant „abstract” si fara corpul de acolade, doar numele si parantezele rotunde, cu parametri necesari.
– Iata un exemplu de clasa cu o proprietate „protected” o metoda abstracta si una accesor:
<?php
// Definire clasa abstracta
abstract class Fructe {
protected $color; // Proprietate
// Definire metoda abstracta
abstract function Stoc($luna);
// Metoda accesor pt. "color"
public function setColor($c) { $this->color = $c; }
}
?>
– Daca se creaza o instanta de obiect la aceasta clasa (de ex.: $obj = new Fructe();), va genera eroare de genul:
Fatal error: Cannot instantiate abstract class
– Metodele abstracte se creaza doar in clase abstracte.
– Rolul claselor si metodelor abstracte este acela de a crea un model minim de metode obligatorii care trebuie definite in sub-clase normale derivate din ele (cu extends). Metodele abstracte definite in cea parinte trebuie create in orice clasa copil extinsa din cea abstracta, cu acelasi numar de parametri (numele poate fi difereit).
De ex., orice sub-clasa extinsa din clasa Fructe (definita mai sus) trebuie sa contina metoda Stoc() cu un parametru, cum ar fi cea din urmatorul exemplu, denumita Mere.
<?php
// Definire clasa copil, extinsa din cea abstracta
class Mere extends Fructe {
private $kg; // Proprietate
// Metoda obligatorie (seteaza valoarea proprietatii "Kg")
public function Stoc($kg) {
$this->kg = $kg;
}
// Alta Metoda - optionala (returneaza valoarea proprietatii "kg")
public function getKg() {
return $this->kg. ' kg';
}
}
?>
– Deoarece clasa Mere extinde Fructe, trebuie sa contina, pe langa alte elemente, si metodele abstracte declarate in aceea (anume Stoc(), cu un parametru). Daca aceasta sub-clasa nu ar avea metoda Stoc(), va genera eroare de genul:
Fatal error: Class Fructe contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Mere::Stoc) in…
– Sub-clasele care extind o clasa abstracta pot fi utilizate normal, se pot crea si folosi instante de obiect la ele, mostenesc si pot folosi elementele cu atribut „public” si „protected” din cea parinte.
De exemplu:
<?php
// Creare instanta de obiect la clasa Mere si apelare metode
$obj = new Mere();
$obj->Stoc(78);
echo $obj->getKg(); // Afiseaza: 78 kg
?>
2. Interfaces
Ca rol, se poate spune ca Interface este asemanatoare cu clasa „abstract”.
Clasa Interface este folosita ca tipar, sau template pentru clase cu functii similare, care trebuie sa respecte o anumita structura de metode.
Sintetizat, Interface este o clasa cu o lista de metode obligatorii ce trebuie sa fie create in clasele unde este implementata. Toate metodele specificate in „Interface” sunt cu atribut public si trebuie sa fie definite in clasele in care e aplicata, avand acelasi numar de parametri cati sunt indicati in „Interface”.
Creare interface
Clasa interface se creaza similar cu celelalte tipuri de clase. Diferenta e aceea ca la definirea ei, in loc de cuvantul „class” se foloseste cuvantul „interface„; in plus, in corpul ei se scrie doar o lista cu metode publice fara, alt cod.
Sintaxa generala este urmatoarea:
- interface numeInterfata {
public function numeMetoda();
public function altaMetoda()
………..
}
– La declararea metodelor in Interface nu se adauga acoladele sau codul lor, si nici alt atribut diferit de „public”.
Iata un exemplu cu o Interface, denumita „ITest”, in care sunt definite 2 metode: „Links()” si „Tutoriale()”.
<?php
// Definire Interface ITest
interface ITest {
// Lista cu metode
public function Links();
public function Tutoriale($str, $nota);
}
?>
Implementare interface
Dupa ce a fost definit tiparul „interface”, se pot crea clase care implementeaza metodele stabilite in acel tipar, respectand si numarul de parametri.
Implementarea se face adaugand cuvantul implements si numele Interfatei la definirea claselor, dupa numele lor.
class NumeClasa implements numeInterfata {
// Instructiuni
}
Acestea trebuie sa contina in corpul lor toate metodele definite in „interface”, cu atribut „public”, si numarul de parametri stabiliti pt. fiecare (numele la parametri poate fi diferit). Pe langa acestea pot contine si alte metode.
Iata un exemplu cu o clasa care implementeaza interfata ITest creata mai sus.
<?php
// Creare clasa care aplica Interfata ITest
class WebDevelopment implements ITest {
// Definire proprietate 'link' (cu atribut "protected")
protected $link = 'www.CursPHP.net';
/* Definire metodele obligatorii (Links si Tutoriale), din interface */
// Returneaza valoarea proprietatii 'site'
public function Links() {
return $this->link;
}
// Returneaza valoarea unei variabile din ea ($re), ce preia argumentele transmise
public function Tutoriale($gen, $nota) {
$re = $gen. '-'. $nota;
return $re;
}
// Se pot crea si alte metode, suplimentare
// Aceasta modifica valoare proprietatii "link"
public function setLink($link) {
$this->link = $link;
}
}
?>
– Metodele obligatorii (aici „Links()” si „Tutoriale()”) respecta exact numarul de parametri stabiliti in „interface” „ITest”. Alte metode (aici „setLink()”) si proprietati sunt optionale, in functie de rolul fiecarei clase.
– Numele parametrilor nu conteaza (observati ca in loc de $str s-a folosit $gen), dar numarul lor trebuie sa fie aceleasi ca in „interface”.
– Daca vreuna din conditii nu ar fi respectata in clasa, cum ar fi: nedefinirea unei metode, adaugarea de parametru in plus sau minus; scriptul genereaza eroare.
Astfel, implementarea de „interface” este utila mai ales cand sunt create mai multe clase cu roluri similare si dorim ca acestea sa aibe toate o anumita ordonare si structura minima de metode, mai usor de retinut.
3. Interface ca tip de date
Interfata poate fi utilizata si ca tip de data la parametri de functii, astfel, acel parametru poate fi utilizat ca instanta de obiect la orice clasa din cele ce folosesc acea „interface”.
Se intelege mai bine din urmatorul exemplu, in care e creata si folosita inca o clasa (LimbiStraine) ce aplica Tiparul din „ITest”; contine o proprietate si metodele obligatorii stabilite.
<?php
// Creare clasa care aplica Interfata ITest
class LimbiStraine implements ITest {
// Definire proprietate
protected $adr = 'www.CursPHP.net/';
/* Definire metodele obligatorii (Links si Tutoriale), din interface */
// Returneaza expresia 'Cale buna'
public function Links() {
return'Cale buna';
}
// Returneaza valoarea unei variabile din ea (re), ce preia argumentele "nr", "gen" si proprietatea "adr"
public function Tutoriale($gen, $nr) {
$re = $nr.'-'. $this->adr. $gen;
return $re;
}
}
?>
Intr-un script PHP se scrie urmatorul cod:
<?php
// Se includ fisierele cu clasele create mai sus (daca sunt in fisiere externe): ITest (Interfata), WebDevelopment si LimbiStraine
include('interf.ITest.php'); // Interface
include('class.WebDevelopment.php');
include('class.LimbiStraine.php');
// Creare functie care accepta doar argument cu obiect la clasele care au implementata Interfata "ITest"
function cursuri(ITest $obj) {
// Apeleaza metodele comune (stabilite in ITest) prin parametru $obj
echo '<br />'. $obj->Links();
echo '<br />'. $obj->Tutoriale('php-mysql', 4);
}
// Creare instante de obiect la clasele folosite
$web_development = new WebDevelopment();
$limbi_straine = new LimbiStraine();
// Apeleaza functia cu instantele de obiect ale claselor ce au aplicat ITest
cursuri($web_development); // "www.CursPHP.net" si "php-mysql-4"
cursuri($limbi_straine); // "Cale buna" si "4-www.CursPHP.net/php-mysql"
?>
– Functia „cursuri()” creata cu aceasta formula intre acolade „function cursuri(ITest $obj)” face ca ea sa accepte ca argument doar obiect care are implementat „ITest”.
– Observati ca apeland functia cu argumente diferite, reprezentand numele instantelor la clase, foloseste parametru $obj ca instanta la clasa respectiva, si poate apela aceleasi metodele („Links()” si „Tutoriale()”) pt. fiecare deoarece aceste fiind specificate in „interface” ele trebuie sa existe in fiecare clasa ce apartine acelei Interfate, cu acelasi numar de parametri.
– Prin aceasta tehnica nu mai e nevoie de a crea aceeasi functie pt. fiecare instanta.
Acest exemplu va afisa in browser urmatorul rezultat:
www.CursPHP.net
php-mysql-4
Cale buna
4-www.CursPHP.net/php-mysql
Functii cu Parametri object si array
In mod general, o functie se creaza cu sintaxa:
function nume_functie(parametri) {
// Instructiuni
}
– Datele din parametri pot fi de diferite tipuri: numere, siruri, matrice (Array) sau chiar un obiect intreg. Pentru a verifica tipul de date primit la parametri, se pot folosi functii PHP specifice, de tip „is_„, precum: is_string(), is_array(), is_object(), etc.
Pentru object si array exista si o alta varianta, specificarea tipului de date permis o data cu parametru, cu formula:
function nume_functie(NumeClasa $parametru) { }
Sau pt. Array
function nume_functie(array $parametru1, array $parametru2, …) { }
– Aceste formule verifica si asigura ca datele din $parametru sa fie o instanta de obiect la o anumita clasa, specificata la NumeClasa, sau, la cealalta sintaxa, de tip array.
Pentru a intelege mai bine, studiati exemplu urmator si comentariile din cod.
<?php
// Definire clasa AClas
class AClas {
public function aMet() {
return 'Metoda clasa AClas';
}
}
// Functie definita sa accepte doar instante de obiect ale clasei AClas (si sub-clase ale ei)
function fCls(AClas $objPar) {
echo $objPar->aMet(). '<br />';
}
// Functie definita sa accepte doar date de tip Array
function fArr(array $arrPar1, array $arrPar2) {
print_r($arrPar1);
echo '<br />';
print_r( $arrPar2);
}
// Creare instanta de obiect la clasa AClas
$obj = new AClas();
fCls($obj); // Apeleaza functia cu aceast obiect
// Definire variabile de tip Array si apelare cu ele functia fArr()
$arr1 = array('php', 'mysql', 'www.CursPHP.net');
$arr2 = array('cursuri', 'tutoriale');
fArr($arr1, $arr2);
?>
– Parametru $objPar al functiei fCls() reprezinta o instanta de obiect la clasa AClas, astfel, prin el pot fi apelate metode si parametri din aceasta clasa.
– Iar functia fArr() trebuie apelata cu doua argumente, ambele de tip Array.
– In browser va afisa:
Metoda clasa AClas
Array ( [0] => php [1] => mysql [2] => www.CursPHP.net )
Array ( [0] => cursuri [1] => tutoriale )
– Daca la apelarea functiei fCls(), in loc de o instanta de obiect la clasa AClas se adauga alt tip de date la argument (sir, numar, obiect de alta clasa, etc.), va genera eroare de genul:
Catchable fatal error: Argument 1 passed to fCls() must be an instance of AClas, …
Pe langa parametri object si array special definiti pot fi adaugati si parametri simpli.
De ex.:
function Functie(array $arr, $p2, $p3) { }
Metode de clasa, cu parametri object si array
Aceasta formula, cu specificarea tipului de parametri permisi (obiect la o anume Clasa sau array), poate fi utilizata si la metodele din clase, care sunt tot functii.
De exemplu, metoda „bObj()” din exemplu urmator accepta ca argument doar instante de obiect ale clasei AClas si prin acesta poate apela metoda „aMet()” din clasa AClas, iar metoda „bArr()” accepta doar date de tip Array.
<?php
// Definire clasa AClas
class AClas {
public function aMet() {
return 'Metoda clasa AClas';
}
}
// Definire clasa BClas
class BClas {
// Metoda definita sa accepte la parametru $obj_par doar elemente ce apartin unui obiect de clasa AClas
public function bObj(AClas $obj_par) {
return $obj_par->aMet(); // Returneaza apelul metodei aMet() din AClas
}
// Metoda definita sa accepte la parametru $arr_par doar date de tip Array
public function bArr(array $arr_par) {
print_r($arr_par); // Afiseaza structura elementelor din $arr_par
}
}
// Creare instanta de obiect la clasa AClas
$objAC = new AClas();
// Creare instanta de obiect la clasa BClas
$objBC = new BClas();
// Apeleaza metoda bObj() din BClas cu instanta la AClas si cealalta cu un Array
echo $objBC->bObj($objAC). '<br />';
echo $objBC->bArr( array('cursuri', 'tutoriale') );
?>
– Explicatiile necesare sunt in cod.
– Scriptul va afisa urmatorul rezultat:
Metoda clasa AClas
Array ( [0] => cursuri [1] => tutoriale )
Inlantuire mai multe metode in PHP OOP
• Inlantuire cu Metoda Statica
Aceasta lectie arata cum se pot accesa mai multe metode inlantuite in PHP OOP.
Inlantuirea metodelor inseamna accesarea mai multor metode, sau functii ale unei clase, intr-o singura instructune.
$obiect->metoda_1()->metoda_2()
Cerinta prin care se pot accesa metode inlantuite este ca metoda precedenta sa returneze instanta de obiect, folosind: return $this in codul metodei precedente (metoda_1() ).
– Iata un exemplu, o clasa PHP prin care se pot calcula aria si perimetrul dreptunghiului (vedeti comentariile din cod si testati-l).
class Rectangle {
public $x = 0;
public $y = 0;
// seteaza valori pentru laturile $x si $y
public function setXY($x, $y){
$this->x = $x;
$this->y = $y;
return $this; // returneaza instanta de obiect
}
// returneaza aria
public function area(){
return $this->x * $this->y;
}
// returneaza perimetru
public function perimeter(){
return 2 * ($this->x + $this->y);
}
}
// creaza o instanta de obiect a clasei
$obR = new Rectangle;
// afiseaza aria si perimetru
echo $obR->setXY(3, 4)->area(); // 12
echo '<br/>'. $obR->setXY(3, 4)->perimeter(); // 14
• Se pot apela mai mult de doua metode inlantuite, tehnica e aceeasi, toate metodele accesate precedent trebuie sa returneze instanta de obiect.
– Iata un exemplu de inlantuire trei metode. O clasa PHP care defineste un tag HTML, cu ID, atribut „class” si continut (studiati codul si testati-l).
class setTag {
private $id = ''; // atributul id
private $class = ''; // atributul class
// seteaza $id
public function setId($id){
$this->id = ' id="'. $id .'"';
return $this; // returneaza instanta de obiect
}
// seteaza $class
public function setClass($class){
$this->class = ' class="'. $class .'"';
return $this; // returneaza instanta de obiect
}
// returneaza tag-ul HTML si continutul
public function getTagCnt($tag, $cnt){
return '<'. $tag .$this->id. $this->class .'>'. $cnt .'</'. $tag. '>';
}
}
// creaza o instanta de obiect a clasei
$obTag = new setTag;
// variabile cu tipul tag-ului si continut
$tag = 'div';
$cnt = 'http://www.CursPHP.net';
// apeleaza metodele inlantuite pt. setare ID, "class", creaza un <div> cu aceste atribute si continut
echo $obTag->setId('some_id')->setClass('cls')->getTagCnt($tag, $cnt);
/* Rezultat:
<div id="some_id" class="cls">http://www.CursPHP.net</div>
*/
Instructiunea cu metodele inlantuite din codul de mai sus:
echo $obTag->setId(‘some_id’)->setClass(‘cls’)->getTagCnt($tag, $cnt);
E la fel cu acest cod:
// seteaza pe rand ID-ul, "class" si afiseaza tag-ul cu continutul
$obTag->setId('some_id');
$obTag->setClass('cls');
echo $obTag->getTagCnt($tag, $cnt);
Inlantuire cu Metoda Statica
Pentru a inlantui o metoda statica trebuie ca metoda statica sa returneze instanta clasei, folosind: return new self.
In instructiunea de apelare a metodei statice se foloseste direct numele clasei.
Sintaxa:
numeClasa::metodaStatica()->altaMetoda()
– Exemplu, o clasa PHP cu o metoda statica ce seteaza valoarea la o proprietate statica privata (private nu poate fi accesat direct in afara clasei), si o metoda publica ce returneaza valoarea proprietatii private.
<?php
class clsData {
// proprietate privata, nu poate fi accesata direct in afara clasei
private static $data;
// metoda statica, seteaza valoarea pt. $data
public static function setData(){
self::$data = 'http://www.CursPHP.net/php-mysql/';
return new self; // returneaza instanta clasei
}
// metoda ce returneaza valoarea din $data
public function getData(){
return self::$data;
}
}
// acceseaza metoda getData() dupa /legat de setData()
echo clsData::setData()->getData(); // http://www.CursPHP.net/php-mysql/
PHP getElementById si getElementsByTagName
• getElementsByTagName()
getElementById si getElementsByTagName sunt metode ale clasei PHP DOMDocument . Aceste metode pot fi utilizate in PHP pentru a lucra cu elemente /tag-uri HTML.
– Inainte de a utiliza metodele clasei PHP DOMDocument, trebuie sa incarcati documentul HTML intr-un obiect DOMDocument, precum in acest cod:
// creaza obiectul DOMDocument
$dochtml = new DOMDocument();
// incarca continutul dintr-o pagina (sau fisier) HTML
$dochtml->loadHTMLFile('filename.html');
// SAU, incarca elementele HTML stocate intr-un sir
$strhtml = '<html><body>Tag-uri si continut.<br></body></html>';
$dochtml->loadHTML($strhtml);
– Variabila $dochtml contine un obiect in care sunt toate elementele din documentul HTML, intr-o structura ierarhica. Dupa ce e definit acest obiect, se pot aplica la el metodele clasei DOMDocument ca sa accesati elementele HTML (dupa cum puteti vedea in exemplele urmatoare).
– Este indicat sa aveti codul HTML corect format, altfel va genera erori E_WARNING daca sunt gasite tag-uri sau atribute neinchise.
Pentru a traversa un obiect PHP, se foloseste instructiunea foreach().
getElementById
Functia getElementById(‘ID’) returneaza un obiect ce contine elementul cu ID-ul specificat, sau NULL daca elementul nu e gasit.
Aceasta functie este utila cand doriti sa preluati continutul, sau atributele dintr-un element HTML cu un anumit ID.
– Proprietatea nodeValue se poate folosi pt a obtine continutul elementului returnat de getElementById().
– Proprietatea tagName (sau nodeName) se poate folosi pt a obtine numele tag-ului.
Exemplu, preia numele tag-ului si continutul unui element cu un anumit ID:
<?php
$strhtml = '<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>PHP getElementById, getElementsByTagName</title>
</head>
<body>
<div id="dv1">www.CursPHP.net</div>
</body></html>';
// creaza obiectul DOMDocument si incarca HTML dintr-un sir
$dochtml = new DOMDocument();
$dochtml->loadHTML($strhtml);
// preia elementul cu id="dv1"
$elm = $dochtml->getElementById('dv1');
// preia numele tag-ului si continutul
$tag = $elm->tagName;
$cnt = $elm->nodeValue;
echo $tag. ' - '. $cnt; // div - www.CursPHP.net
?>
getElementsByTagName
Functia getElementsByTagName(‘tag’) returneaza un obiect cu toate elementele cu acelasi nume de „tag”. Argumentul special ‘*’ preia toate tag-urile.
Aceasta functie este utila cand doriti sa preluati continutul, sau atributele mai multor elemente HTML cu acelasi <tag>.
– Metoda getAttribute(‘atribut’) se foloseste pt a obtine valoarea unui anumit atribut.
Exemplu, preia si afiseaza ID-ul si continutul fiecarui DIV:
<?php
$strhtml = '<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>PHP getElementById, getElementsByTagName</title>
</head>
<body>
<div id="cweb">www.PHPCursWeb.net</div>
<p>Curs gratuit PHP</p>
<div id="mp">www.CursPHP.net</div>
</body></html>';
// creaza obiectul DOMDocument si incarca HTML dintr-un sir
$dochtml = new DOMDocument();
$dochtml->loadHTML($strhtml);
// preia toate DIV-urile
$divs = $dochtml->getElementsByTagName('div');
// parcurge obiectul cu toate DIV-urile
foreach($divs as $div) {
// preia si afiseaza ID-ul si continutul fiecarui DIV
$id = $div->getAttribute('id');
$cnt = $div->nodeValue;
echo $id. ' - '. $cnt. '<br/>';
}
?>
Rezultat:
cweb – www.PHPCursWeb.net
mp – www.CursPHP.net
– Se poate folosi /incarca doar o parte din documentul HTML.
Exemplu 2. Incarca un sir ce contine doar sectiunea BODY, retine intr-un Array continutul fiecarui paragraf (<p>) cu class=”cls”.
<?php
$strhtml = '<body>
<p class="cls">Curs gratuit PHP</p>
<p class="cls">URL: http://www.PHPCursWeb.net</p>
<p>Paragraph without class.</p>
<div>www.CursPHP.net</div>
<p class="cls">PHP getElementById si getElementsByTagName</p>
</body>';
// creaza obiectul DOMDocument si incarca HTML dintr-un sir
$dochtml = new DOMDocument();
$dochtml->loadHTML($strhtml);
// preia toate tag-urile <p>
$prgs = $dochtml->getElementsByTagName('p');
$pcls = array();
// parcurge obiectul cu toate paragrafele
foreach($prgs as $prg) {
// daca paragraful curent are class="cls", il adauga in array-ul $pcls
if($prg->getAttribute('class') == 'cls') {
$pcls[] = $prg->nodeValue;
}
}
// afiseaza array-ul $pcls
print_r($pcls);
// Array ([0] => Curs gratuit PHP [1] => URL: http://www.PHPCursWeb.net [2] => PHP getElementById si getElementsByTagName )
?>
Lucru cu atribute HTML in PHP
• hasAttribute
• setAttribute
• removeAttribute
Clasa PHP DOMElement contine metode care pot fi utilizate pentru: citire, setare si stergere atribute in documentul HTML incarcat in obiect DOMDocument.
Pentru a traversa un obiect PHP, se foloseste instructiunea foreach().
getAttribute
Functia getAttribute(‘attr’) returneaza valoarea atributului specificat, sau un sir gol daca atributul „attr” nu e gasit.
– Aceasta metoda poate fi aplicata la un element HTML (sau XML) dintr-un obiect DOMDocument.
– Se poate utiliza functia getElementsByTagName(‘tag’) pt a prelua toate elementele cu un anumit <tag>.
– Ca sa preluati elementul cu un anumit ID, se foloseste metoda getElementById(‘ID’).
Exemplu, obtine valoarea „href” din fiecare <a> din #menu:
<?php
// sir cu continut HTML
$strhtml = '<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>PHP getAttribute</title>
</head>
<body>
<ul id="menu">
<li><a href="http://www.PHPCursWeb.net/" title="Cursuri programare web">PHPCursWeb.net</a></li>
<li><a href="http://www.CursPHP.net/" title="Cursuri gratuite Jocuri Anime">CursPHP.net</a></li>
<li><a href="http://www.php.net/" title="PHP Website">php.net</a></li>
</ul>
</body></html>';
// creaza obiectul DOMDocument si incarca HTML din sir
$dochtml = new DOMDocument();
$dochtml->loadHTML($strhtml);
// preia elementul cu id="menu"
$menu = $dochtml->getElementById('menu');
// obtine toate tag-urile <a> din $menu
$atgs = $menu->getElementsByTagName('a');
// parcurge obiectul cu toate <a> in $menu
foreach($atgs as $atag) {
// afiseaza valoarea "href"
echo $atag->getAttribute('href'). '<br/>';
}
?>
Rezultat:
http://www.PHPCursWeb.net/
http://www.CursPHP.net/
http://www.php.net/
hasAttribute
Functia hasAttribute(‘attr’) returneaza TRUE daca atributul transmis exista, altfel FALSE.
– Aceasta metoda e utila cand se doreste preluarea valorii unui anumit atribut, pentru a evita erorile, verifica daca acel atribut exista.
– Se poate folosi /incarca si doar o parte din documentul HTML.
Exemplu. Incarca un sir ce contine doar sectiunea BODY, afiseaza ID-ul si continutul DIV-urilor care au un atribut ID:
<?php
// sir cu continut HTML
$strhtml = '<body>
<div id="dv1">Curs gratuit PHP-MySQL.</div>
<div>Lucru cu atribute HTML in PHP.</div>
<div id="did">Resurse Web Development.</div>
</body>';
// creaza obiectul DOMDocument si incarca HTML din sir
$dochtml = new DOMDocument();
$dochtml->loadHTML($strhtml);
// obtine toate tag-urile DIV
$divs = $dochtml->getElementsByTagName('div');
// parcurge obiectul cu toate DIV-urile
foreach($divs as $div) {
// daca $div are ID, obtine si afiseaza ID-ul si continutul
if($div->hasAttribute('id')) {
$id = $div->getAttribute('id');
$cnt = $div->nodeValue;
echo $id. ' - '. $cnt. '<br/>';
}
}
?>
Rezultat:
dv1 – Curs gratuit PHP-MySQL.
did – Resurse Web Development.
setAttribute
Functia setAttribute(‘attr’, ‘value’) seteaza valoarea „value” la atributul „attr”. Daca atributul nu exista, il creaza.
– Aceasta metoda e utila cand doriti sa creati un atribut intr-un tag, sau sa dati alta valoare atributului respectiv.
– Cu metoda $doc->saveHTML() se poate adauga intr-un sir continutul dintr-un nod DOMDocument cu HTML. De obicei e necesara dupa efectuarea anumitor modificari in obiectul DOMDocument.
– Acest cod:
$dochtml->getElementsByTagName(‘body’)->item(0)
returneaza un nod DOMDocument cu elementul <body>. Este util daca doriti sa lucrati doar cu elementul <body> (incluzand tot continutul din el), de exemplu pt a salva intr-un sir continutul BODY.
Exemplu, seteaza class=”newcls” la toate paragrafele (<p>):
<?php
$strhtml = '<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>PHP setAttribute</title>
</head>
<body>
<p class="cls">Lectii gratuite PHP-MySQL.</p>
<p>URL: http://www.PHPCursWeb.net/php-mysql/</p>
<p>Resurse Web Development.</p>
</body></html>';
// creaza obiectul DOMDocument si incarca HTML din sir
$dochtml = new DOMDocument();
$dochtml->loadHTML($strhtml);
// obtine toate tag-urile <p>
$prgs = $dochtml->getElementsByTagName('p');
// parcurge obiectul cu toate paragrafele
foreach($prgs as $prg) {
// seteaza /creaza class="newcls" la fiecare <p>
$prg->setAttribute('class', 'newcls');
}
// obtine obiect cu elementul <body> (cu tot continutul din el)
$body = $dochtml->getElementsByTagName('body')->item(0);
// adauga continutul $body intr-un sir si-l afiseaza
$strbody = $dochtml->saveHTML($body);
echo $strbody;
?>
Rezultat:
<body>
<p class="newcls">Lectii gratuite PHP-MySQL.</p>
<p class="newcls">URL: http://www.PHPCursWeb.net/php-mysql/</p>
<p class="newcls">Resurse Web Development.</p>
</body>
removeAttribute
Functia removeAttribute(‘attr’) sterge atributul „attr” din element. Returneaza TRUE la succes, sau FALSE in caz de esec.
Exemplu, sterge atributul „class” din fiecare tag <p> cu class=”cls”:
<?php
// sir cu continut HTML
$strhtml = '<body>
<p class="cls">Lectii gratuite PHP-MySQL.</p>
<p class="othercls">Cursuri programare web.</p>
</body>';
// creaza obiectul DOMDocument si incarca HTML din sir
$dochtml = new DOMDocument();
$dochtml->loadHTML($strhtml);
// obtine toate tag-urile <p>
$prgs = $dochtml->getElementsByTagName('p');
// parcurge obiectul cu toate paragrafele
foreach($prgs as $prg) {
// daca elementul curent are class="cls", sterge atributul
if($prg->hasAttribute('class') && $prg->getAttribute('class') == 'cls') {
$prg->removeAttribute('class');
}
}
// obtine obiect cu elementul <body> (cu tot continutul din el)
$body = $dochtml->getElementsByTagName('body')->item(0);
// adauga continutul $body intr-un sir si-l afiseaza
$strbody = $dochtml->saveHTML($body);
echo $strbody;
?>
Rezulta:
<body>
<p>Lectii gratuite PHP-MySQL.</p>
<p class="othercls">Cursuri programare web.</p>
</body>
Documente XML
1. Despre XML
XML vine de la Extensible Markup Language. XML e o forma de SGML (Standard Generalized Markup Language), pe scurt, acesta defineste o sintaxa pentru structurarea datelor (un limbaj) pe care si omul si calculatorul sa le poata citi.
Fiind un curs de PHP, explicatiile despre XML vor fi mai putine, scurte si simple, cat e necesar pentru a se intelege ce e si cum poate fi utilizat cu PHP.
Ca sa intelegeti cam ce este XML si ce se poate face cu el, ganditi-va ca e similar cu HTML-ul, dar fara aspect grafic, in sensul ca structura acestuia se formeaza pe baza unor tag-uri (elemente), precum <h1>, <div>, etc. in HTML, si care pot contine atribute (sau identificatori), iar in acelasi timp este o mini baza de date, deoarece scopul documentelor XML e acela de a aranja si stoca date intr-o anumita ordine si structura erarhica care sa poata fi citite si prelucrate de un alt limbaj, precum PHP.
Documentele XML pot fi create, scrise, folosind un editor simplu de texte (precum Notepad).
Dupa cum puteti vedea in modelul de mai jos, un document XML e asemanator cu unul HTML (daca stiti deja acest limbaj). Datele sunt incadrate in niste tag-uri. Spre deosebire de HTML, in XML denumirea tag-urilor (tehnic elemente) nu e stricta, putand fi folosite nume alese de fiecare in functie de optiunea fiecaruia pentru recunoasterea datelor ce vor fi scrise, care respecta cateva reguli minime.
Aceste reguli sunt:
- Documentul XML trebuie sa inceapa cu sintaxa:
- <?xml version=”1.0″?>
urmata de un element de baza (radacina) care va cuprinde toate celelalte elemente (precum <html></html>), in exemplu de mai jos <book></book>
- Elementele trebuie sa aiba tag-uri de inchidere sau inchidere singulara (slash la sfarsitul tag-ului: <… />) si sa fie ierarhice, astfel e corect: <x> <y>…</y> </x> sau <x /> <y>…</y> (incorect <x> <y> </x> sau <x> <y> </x> </y>)
- Caracterele &, <, >, ‘, „ sunt restrictionate in interiorul datelor, putand fi folosite prin escapare, cu forma: &, <, >, ', "
- XML este case-sensitive, astfel <tag> e diferit de <Tag>, de aceea e indicat sa folositi litere mici la elemente si atribute pentru a evita confuzia.
– Exemplu de document XML:
<?xml version="1.0"?>
<book>
<publisher>Editura</publisher>
<title>Titlu carte</title>
<chapter title="Capitol carte">
<section title="Sub capitol">
<paragraph>
O fraza din sectiunea acestui sub-capitol.
</paragraph>
<paragraph>
Alta fraza din acelasi sub-capitol.
</paragraph>
</section>
</chapter>
</book>
– Acesta este o structura XML creata pentru stocarea ordonata a unor date despre carti.
Datele astfel stocate (cum puteti vedea in exemplul de sus) pot fi relativ usor citite si intelese de om (putand fi modificate simplu daca e nevoie) dar si de un limbaj de programare (PHP, ASP) care le preia din fisierul .xml, le prelucreaza si le poate aranja, manipula si transmite catre o alta aplicatie, precum un navigator (browser) web.
In practica se folosesc de obicei pentru stocarea datelor baze de date SQL, iar acest format XML este de preferat cand se doreste utilizarea acestor date de catre mai mullti agenti, in general in scop de citire; transmiterea fiind mai rapida si economica, de exemplu: Stiri, Meteo, Clasamente, etc.
Aici apare rolul important al limbajului PHP, care, dupa ce a preluat aceste date din fisierul .xml (ce poate fi pe alt server) le poate include intr-o pagina HTML pentru a fi afisate in browser, sau introduce intro alta baza de date mai mare.
PHP are functii speciale pentru citirea, recunoasterea si manipularea datelor din format XML si chiar pentru crearea, scrierea de documente XML (daca are permisiuni de scriere pe server). Vor fi aratate in tutorialele (lectiile urmatoare.
2. Documente XML si DTD
Cerintele, criteriile, pentru scrierea unui document XML corect sunt simple si minime. Totusi, un document XML valid si usor de inteles are nevoie sa urmeze anumite reguli stabilite, cunoscute generic ca DTD (Document Type Definition).
Ca sa intelegeti ce este si la ce e nevoie DTD, studiati urmatorul exemplu in comparatie cu cel de sus.
<?xml version="1.0"?>
<book title="Nume carte">
<publisher name="Nume Editura"/>
<chapter number="8">
<chapter_title>Titlu capitol</chapter_title>
<p>
<sentence>O fraza din sectiunea acestui sub-capitol.</sentence>
<sentence>Alta fraza din acelasi sub-capitol.</sentence>
</p>
</chapter>
</book>
– La prima vedere pare similar, dar, desi datele esentiale transmise sunt aceleasi, structura poate fi diferita. Se observa elemente cu alte denumiri si adaugarea de atribute.
Pentru a folosi datele din documentele XML, trebuie sa le cunoasteti structura aranjarii lor si forma ierarhica, astfel puteti adauga noi date (de exemplu aici carti) care trebuie sa respecte acelasi format. Iar in cazul unor documente mai mari, cu ierarhii mai multe, intelegerea lor devine mai greoaie si va dura mai mult timp.
Aici intervine rolul DTD, o forma de explicare pe scurt a structurii aranjarii datelor si relatia dintre ele. Adica, scrierea sub forma unei liste a specificatiilor exacte despre cum sunt elementele legate intre ele, ce tip si nume au fiecare si ce atribute sunt necesare.
De exemplu, pentru modelul de sus, daca cineva doreste sa-l foloseasca si sa adauge noi carti, am putea scrie o descriere astfel:
- Obiectul radacina al acestu document este „book”
- „book” are doar un atribut „title”
- „book” e compus direct din doua elemente: „publisher” si chapter”
- „publisher” are doar un atribut „name”
- „chapter” are un atribut „number” si doua elemente „chapter_title” si „p”
- „p” poate contine mai multe elemente „sentence”
– Astfel, dand o copie a acestei liste oricui are nevoie de acest document XML, va ajuta la intelegerea mai rapida si usoara a structurii datelor pentru a le folosi sau adauga corect altele noi.
Se poate lucra in PHP cu datele din XML dupa ce a fost inteleasa structura lor.
Setul de reguli DTD (Document Type Definition) poate fi specificat (scris) direct in documentul XML (precum documentatiile in PHP), intr-un tag special !DOCTYPE (document type declaration) si cu o sintaxa specifica.
Exemplu listei de sus este pentru intelegerea de catre alte persoane, dar exista o sintaxa standard DTD care se adauga de obicei la inceputul fisierului XML. Pentru obiectul acestui curs nu e nevoie de cunostinte mai multe despre asta, vedeti totusi cum e in exemplul urmator.
Ca sa intelegeti cum se poate adauga setul de reguli standard DTD direct in XML, vedeti exemplul urmator (partea scrisa ingrosat).
<?xml version="1.0"?>
<!DOCTYPE recipe [
<!ELEMENT recipe (ingredients, directions, servings)>
<!ATTLIST recipe name CDATA #REQUIRED>
<!ELEMENT ingredients (#PCDATA)>
<!ELEMENT directions (#PCDATA)>
<!ELEMENT servings (#PCDATA)>
]>
<recipe name ="mancare">
<ingredients>Legume</ingredients>
<ingredients>Paine</ingredients>
<directions>Adauga la pachet</directions>
<servings>12</servings>
</recipe>
– Documentul XML e impartit in 3 sectiuni. Prima sectiune e linia standard XML. A doua sectiune e setul intern de reguli DTD, marcat cu linii care incep cu <!. A treia sectiune sunt datele XML.
Regulile interne DTD sunt scrise, incadrate de paranteze patrate in interiorul <!DOCTYPE recipe […]> (document type declaration), ‘recipe” fiint obiectul (elementul) radacina.
Daca aveti mai multe documente cu aceeasi structura, se poate folosi un singur DTD dintr-un fisier extern, decat in fiecare, mai usor de actualizat in urma unei modificari.
Si in cazul utilizarii unui DTD extern, trebuie folosit !DOCTYPE care sa precizeze locatia acestuia.
Iata 2 exemple, in primul, SYSTEM indica locatia pe server, iar in al doilea, PUBLIC specifica un DTD standardizat (intalnnit si in documente HTML sau XHTML):
<!DOCTYPE recipe SYSTEM „recipe.dtd”>
si
<!DOCTYPE HTML PUBLIC „-//W3C//DTD HTML 4.01 Transitional//EN” „http://www.w3.org/TR/html4/loose.dtd”>
In cazul aceluiasi DTD de mai sus, dar in fisier extern, „recipe.dtd” ar arata astfel:
<!ELEMENT recipe (ingredients, directions, servings)>
<!ATTLIST recipe name CDATA #REQUIRED>
<!ELEMENT ingredients (#PCDATA)>
<!ELEMENT directions (#PCDATA)>
<!ELEMENT servings (#PCDATA)>
– Fara !DOCTYPE si paranteze patrate.
– Prin urmare, un document XML valid este acela care are un format corect, respecta minimile reguli de sintaxa, dar contine si un DTD.
Aceasta a fost partea teoretica, de scurta introducere in formatul XML, in tutorialul urmatoar e prezentate aspectul practic si modul de lucru cu PHP.
Lucru cu XML – DOM
- Pentru exemplele prezentate e nevoie de PHP 5+
1. Module de lucru cu XML
Pentru a prelucra in PHP datele dintr-un document XML trebuie ca acesta sa aibe structura si sintaxa corecta comform standardului XML, nu e nevoie sa fie strict valid, adica sa contina si DTD (vedeti explicatii despre asta in lectia precedenta), dar indicat e sa fie si valid.
Sunt trei moduri (module) pentru lucrul cu XML: SimpleXML, DOM (Document Object Model) si SAX (Simple API for XML); toate trei sunt incluse in PHP. Fiecare are avantaje si minusuri, pot fi folosite oricare din ele pentru a lucra cu datele din XML, pt. a crea, extinde si modifica documente XML.
In continuare iata cate ceva, pe scurt, despre aceste module, dupa care va fi explicat DOM, iar in lectia urmatoare si celelalte doua.
SAX
- – SAX este mai usor de invatat, dar trateaza in esenta XML ca un sir de date. Acest lucru face dificila adaugarea de noi elemente sau atribute, ori modificarea unuia anume.
- – SAX e util pt. lucruri repetitive ce pot fi aplicate tuturor elementelor de acelasi tip. De exemplu, inlocuirea uni anumit element cu tag HTML pt. a transforma XML in HTML.
DOM
- – Extensiile PHP DOM citesc documentul XML si creaza pe baza acestuia, in memorie, un obiect cu o structura ierarhica de tip arbore, incepand cu un element (sau obiect) numit Nod (Node), elementele (obiectele) care sunt cuprinse (incadrate) in acesta se numesc Copii (Children) ai acestui obiect, iar elementele care-l cuprind (contin) pe el se numesc Parinti (Parents). Cu functiile specifice DOM se poate obtine, modifica sau crea oricare din aceasta ierarhie sau continutul, textul din ele. Apoi aceste date se pot folosi independent, fiecare unde este necesar. Dezavantajul poate fi faptul ca foloseste mai multe resurse, memorie.
DOM trebuie sa aibe in memorie tot arborele ierarhic inainte de a incepe analiza documentului XML, fapt ce afecteaza procesarea documentelor XML ce depasesc memoria alocata, dar se poate depasi aceasta limitare prin folosirea unui spatiu de pe hard-disc ca memorie.
SimpleXML
- – SimpleXML lucreaza cel mai bine pentru deschiderea si citirea rapida a datelor unui document XML, converteste elementele si atributele din XML in variabile native PHP (siruri, matrice) care pot fi utilizate dupa cum se face normal cand sunt scrise in PHP.
- – SimpleXML foloseste mai putina memorie decat DOM, economiseste resurse si timp prin faptul ca necesita putine linii de cod, executa mai putine apelari decat fac SAX si DOM. Minusul acestuia sunt unele probleme ce pot apare cand e vorba de elemente imbricate mai adanc.
2. DOM XML
Document Object Model (DOM) e un modul complet pentru crearea, editarea si manipularea datelor din documentele XML. Deoarece aceste date sunt retinute in memorie sub forma de arbore ierarhic, e recomandat ca documentul XML sa fie valid.
Fiecare element e transformat intr-un Obiect si e vazut ca un Nod ce poate avea Continut, Parinti si Copii; incepand cu elementul radacina. La randul lor, fiecare din acestia putand fi un Nod si interpretat ca un Obiect separat, devenind totul o structura legata dar si individuala.
Aceasta structura poate fi modificata cu functii speciale (dintr-o librarie de functii cum e „gnome-libxml2” care sunt implementate in PHP) si rescrisa iar intr-un format XML.
Exemplu 1 – Creare document XML cu PHP
Pentru a intelege despre ce e vorba, vom lua un exemplu practic. Vom crea cu PHP un document XML cat mai simplu, folosind functiile DOM XML. Etapele de lucru sunt urmatoarele:
- 1. Se creaza in memorie un nou obiect XML.
- 2. Se creaza si adauga cateva elemente, un atribut si un continut text. Aici alcatuim o structura cu tag-uri HTML
- 3. Se vor scrie (salva) datele intr-un fisier .xml (denumit „exemplu_dom.xml”) pe server (PHP trebuie sa aiba permisiuni de scriere pe server).
– Codul PHP pentru crearea acestuia este urmatorul. Explicatiile necesare le gasiti in cod.
<?php
$doc = new DomDocument('1.0', 'utf-8'); // Se creaza in memorie un nou obiect DOM
$root = $doc->createElement('html'); // Se creaza primul obiect element, radacina
$root = $doc->appendChild($root); // Se adauga in structura documentului, ca element
$body = $doc->createElement('body'); // Se creaza un alt element, 'body'
$body = $root->appendChild($body); // Se adauga 'body' ca element copil in radacina
$body->setAttribute('bgcolor', '#e8e8fe'); // Se seteaza un atribut pt. elementul doi (body)
$graff = $doc->createElement('p'); // Se creaza un alt element, 'p'
$graff = $body->appendChild($graff); // Se adauga 'p' ca element copil in 'body'
$text = $doc->createTextNode('Un text pentru continut'); // Se creaza un continut text
$text = $graff->appendChild($text); // Se adauga continutul text in 'p'
// Salveaza, scrie datele create in obiectul $doc
// Afiseaza mesaj daca a putut salva fisierul pe server sau nu
if($doc->save("exemplu_dom.xml")) echo 'Documentul exemplu_dom.xml a fost creat';
else echo 'Eroare: documentul exemplu_dom.xml nu a putut fi creat';
?>
– Copiati acest script intr-un fisier .php si apelati-l din browser, daca va crea cu succes fisierul „exemplu_dom.xml” va afisa un mesaj afirmativ.
– Ca sa vedeti rezultatul, deschideti acest fisier cu un editor de text (sau un browser).
Exemplu 2 – Modificare document XML cu PHP
Dupa ce e creat, sau aveti deja un document XML, poate apare necesitatea de a modifica ceva la el, schimbarea continutului unui element, adaugarea unui element nou, sau altele.
In urmatorul exemplu puteti invata cum se poate face cu PHP DOM cateva modificari la datele dintr-un document XML si salvate in alt fisier .xml.
Va fi folosit documentul creat in primul exemplu, la care va fi modificat continutul text din elementul (tag-ul) ‘p’ si va fi adaugat un alt element ‘div’ in acelasi parinte unde e si ‘p’. Explicatiile necesare le gasiti in cod.
Etapele sunt urmatoarele:
- 1. Se creaza un nou obiect in memorie si se adauga in el datele dintr-un document XML existent.
- 2. Se preia si parcurg elementele (care devin Nod-uri) din documentul adaugat.
- 3. Cand parcurgerea ajunge la elementul caruia dorim sa-i adaugam un nou continut text, adauga (modifica) pe cel existent, creaza un nou element cu nume si text pe care-l adauga dupa cel modificat (in acelasi parinte)
<?php
$file = 'exemplu_dom.xml'; // Calea si numele fisierului .xml
$doc = new DOMDocument(); // Creaza un nou obiect in memorie
$doc->load($file); // Incarca datele din $file in obiectul nou creat
$get_elms = $doc->getElementsByTagName("*"); // Preia toate elementele ("*") stocate in obiect
$nr_elms = $get_elms->length; // Obtine numarul de elemente (Nodes) preluate
// Parcurge variabila cu obiectul ce stocheaza elementele (Nod-urile)
for($i = 0; $i<$nr_elms; $i++) {
$node = $get_elms->item($i); // Preia fiecare Nod din parcurgere
$element = $node->nodeName; // Obtine numele elementului
// Daca elementul este 'p', ii adauga alt continut text
if($element=='p') {
$node->nodeValue = 'Un continut text nou';
// Creaza noul element dupa 'p' (in elementul Parinte unde se afla si 'p'), cu nume si continut text
$element_nou = $doc->createElement('div', 'Acesta este elementul nou adaugat');
$node->parentNode->appendChild($element_nou); // Adauga in elementul parinte noul element creat
}
}
// Daca poate salva noul continut XML (din obiectul $doc) intr-un fisier .xml
// Preia continutul si intr-un sir (cu "saveXML()") pt. a afisa rezultatul obtinut
if($doc->save('exemplu2_dom.xml')) {
echo htmlentities($doc->saveXML());
}
// Daca doriti rescrierea primului document XML, inlocuiti 'exemplu2_dom.xml' cu numele aceluia
?>
– O lista cu mai multe functii utile in lucrul cu DOM si XML in PHP gasiti la pagina -> Functii DOM XML
In tutorialul urmator este explicat utilizarea modulului SAX.
Lucru cu XML – SAX
SAX (Simple API for XML) este utilizat pe scara larga pentru a analiza documente XML. E un API bazat pe evenimente. Functiile pentru aceste evenimente nu sunt standard, ci sunt create de utilizator. Utilizatorul creaza un numar de functii ce sunt apelate cand este recunoscut un anumit eveniment.
Analiza documentelor XML cu SAX este unidirectionala. In timp ce analiza parcurge datele XML, sunt recunoscute bucati din XML precum: elemente, atribute, continut text, fiecare fiind un eveniment, iar datele asociate unui eveniment sunt transmise la o functie creata de utilizator, dupa ce functia termina operatiile analiza XML-ului continua. Datele care au fost analizate anterior nu pot fi recitite decat incepand iar parsarea.
Avantajul principal fata de DOM este faptul ca SAX foloseste mai putina memorie si procesarea datelor poate fi mai rapida.
DOM trebuie sa aibe in memorie tot arborele ierarhic inainte de a incepe analiza documentului XML, fapt ce afecteaza procesarea documentelor XML ce depasesc memoria alocata, (dar se poate depasi aceasta limitare in cazul DOM prin folosirea unui spatiu de pe hard-disc ca memorie). In schimb, cantitatea de memorie folosita de SAX depinde de adancimea imbricarii elementelor si de cantitatea de date a atributelor dintr-un element, ambele fiind mai mici decat marimea arborelui, ceea ce-l face o alternativa mai buna in cazul documentelor XML mari dar cu adancime de imbricare mai mica.
1. Utilizarea SAX
Utilizarea SAX depinde in general de scopul prelucrarii documentului XML, deoarece utilizatorul scrie functiile necesare, dar sunt cativa pasi comuni:
- Determinarea evenimentelor care se doresc folosite.
- Scrierea functiilor ce vor fi apelate pentru fiecare eveniment, de cele mai multe ori pentru scrierea datelor, inceputul si sfarsitul unui eveniment.
- Crearea unui parser folosind „xml_parser_create()” si apoi apelarea lui cu „xml_parse()„.
- Eliberarea memoriei cu „xml_parser_free().„.
Urmatorul exemplu arta modul de creare si utilizare a acestor functii de baza. Ca model, va fi folosit urmatorul document XML, stocat intr-un fisier „exemplu_sax.xml”:
<?xml version="1.0" encoding="utf-8"?>
<carti>
<titlu titlul="Titlu Carte" id="1">
<autor nume="Nume Autor" />
<text>Un text din carte</text>
<pret suma="00" />
</titlu>
</carti>
– Cu functiile definite mai jos, vor fi prelucrarte si afisate numele, atributele si continutul text din fiecare element al acxestui document XML.
Documentatia din cod explica detaliat rolul si utilizarea fiecarei functii.
<?php
$file = "exemplu_sax.xml"; // Calea si numele fisierului XML
// Functie apelata la inceputul fiecarui element
// Pe langa $parser (analizatorul), $name e numele elementului
// $ar_attr e un array in care sunt stocate atributele din element [nume]=>valoare
function startElement($parser, $name, $ar_attr) {
// Aici pot fi prelucrate matricea cu atributele ($ar_attr) si numele elementului ($name)
echo "<b>$name -</b> "; // Afiseaza numele elementului
// Daca matricea contine cel putin un atribut, o parcurge
if(count($ar_attr)>0) {
foreach($ar_attr as $atr=>$val) {
echo " $atr => $val ,"; // Preia si afiseaza numele si valoarea fiecarui atribut
}
}
}
// Functie apelata la sfarsitul fiecarui element
// Pe langa $parser (analizatorul), $name stocheaza numele elementului (la inchidere)
function endElement($parser, $name) {
// Aici, daca se mai doreste de facut ceva dupa ce a ajuns la inchiderea elementului
print "\n";
}
// Functie apelata de fiecare data cand sunt intalnite caractere de date (continut text) in element
// Pe langa $parser (analizatorul), $value stocheaza valoarea elementului intalnit (continutul-text)
function characterData($parser, $value) {
// Aici pot fi manipulate datele din $value
echo "$value <br>"; // Afiseaza valoarea transmisa functiei
}
// Se defineste analizatoru care va fi apelat alaturi de functiile pentru evenimente (definite mai sus)
// Pentru a utiliza standardul ISO-8859-1, se sterge parametru 'utf-8'
$simpleparser = xml_parser_create('utf-8');
// Daca se doreste anularea preluarii cu majuscule (se sterge // din fata functiei)
// xml_parser_set_option($simpleparser, XML_OPTION_CASE_FOLDING, 0);
// Evenimentul care apeleaza functiile la inceputul si sfarsitul fiecarui element
xml_set_element_handler($simpleparser, "startElement", "endElement");
// Eveniment ce apeleaza functia "characterData()" cand analiza ajunge la continutul din element
xml_set_character_data_handler($simpleparser, "characterData");
// Deschide fisierul XML pentru citire
if($fo = fopen($file, "r")) {
// Preia continutul fisierului intr-un sir
while ($date_xml = fread($fo, filesize($file))) {
// Transmite datele la parser (analizator)
if (!xml_parse($simpleparser, $date_xml, feof($fo))) {
// Afiseaza eroarea aparuta daca analiza nu poate fi executata
echo xml_error_string(xml_get_error_code($simpleparser));
}
}
fclose($fo); // Elibereaza memoria folosita pt deschiderea fisierului
}
else echo "Nu a putut citi $file";
// Elibereaza memoria folosita la parsare
xml_parser_free($simpleparser);
?>
– Acest script va afisa urmatorul rezultat:
CARTI –
TITLU – TITLUL => Titlu Carte , ID => 1 ,
AUTOR – NUME => Nume Autor ,
TEXT – Un text din carte
PRET – SUMA => 00 ,
– Observati ca numele elementelor si atributelor sunt receptionate si returnate de SAX cu majuscule. In mod initial, SAX foloseste aceste nume cu majuscule iar formatul caracterelor e ISO-8859-1.
Pentru a anula preluarea cu majuscule si folosirea unui alt format (US-ASCII sau UTF-8) se poate utiliza functia „xml_parser_set_option()„, care preia ca prim argument parserul creat, apoi o constanta: XML_OPTION_CASE_FOLDING sau XML_OPTION_TARGET_ENCODING pentru format; al treilea argument este optiunea acelei constante.
De exemplu, pentru anularea preluarii cu majuscule si utilizarea coding-ului UTF-8, se foloseste urmatorul cod la definirea analizatorului:
// Se defineste analizatoru
$simpleparser = xml_parser_create();
// Anuleaza preluarea cu majuscule si foloseste formatul UTF-8
xml_parser_set_option($simpleparser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($simpleparser, XML_OPTION_TARGET_ENCODING, ‘UTF-8’);
– Pentru definirea formatului de codare, se poate specifica direct in functia „xml_parser_create(‘utf-8’)”.
2. Functii SAX
Iata o lista cu cele mai importante functii SAX:
- xml_parser_create([format]) – Creaza parser-ul (analizatorul), pot fi create mai multe in acelasi script. Format e optional, ‘utf-8’ daca se doreste acesta.
- xml_parser_free(parser) – Elibereaza memoria folosita de parametru „parser”, care a fost creat cu „xml_parser_create()”.
- xml_parse(parser, „date_xml” [, final]) – Porneste analiza datelor XML, din „date_xml”, cu analizatorul „parser”. Parametru trei, „final” e optinal, precizeaza ultima bucata de date unde sa se termine analiza.
- xml_get_error_code(parser) – Daca procesarea esueaza, aceasta functie returneaza un cod de eroare din care se poate gasi cauza problemei.
- xml_error_string(errorcode) – Returneaza un sir care specifica eroarea gasita de „xml_get_error_code()”, dat ca parametru.
- xml_set_element_handler(parser, start_element_handler, end_element_handler) – Aceasta functie seteaza evenimentele (functiile definite de utilizator) ce trebuiesc apelate la inceputul, apoi inchiderea, unui element.
- xml_set_character_data_handler(parser, date_handler) – Seteaza evenimentul cu functia ce trebuie apelata cand analiza ajunge la contextul (continutul text) al elementului.
- xml_set_default_handler(parser, handler) – Seteaza evenimentul „default” care e apelat daca nu a fost definita o anume apelare pentru un eveniment.
In tutorialul urmator este explicat utilizarea modulului SimpleXML.
PHP – XML – SimpleXML
SimpleXML a aparut in PHP 5. Lucreaza ca si DOM, cu obiecte, preia tot documentul XML sub forma unui arbore ierarhic in memorie, dar spre deosebire de acesta, e mai flexibil si foloseste mai putina memorie deoarece elementele sunt stocate direct ca variabile PHP (de tip string si array) si astfel pot fi imediat utilizate. Foloseste un minim necesar de cod si are o forma intuitiva a datelor.
– In SimpleXML se lucreaza mult cu functii pentru Array, majoritatea datelor sunt stocate in variabile de tip array.
Este util cand se doreste citirea catorva date dintr-un document XML, a carui structura o cunoasteti, si scrierea altora inapoi.
Ca si in cazul DOM, este indicat ca documentul XML sa aibe un format corect facut, cel mai bine, valid.
1. Citire document XML cu SimpleXML
La inceput se preia documentul XML dintr-un fisier (cu simplexml_load_file().) sau dintr-un sir (cu simplexml_load_string()) care este imediat adaugat sub forma de obiect in memorie.
Apoi se face referire direct la oricare element din obiect, dupa cum puteti vedea in exemplul de mai jos (trebuie sa stiti structura datelor XML si elementele pe care doriti sa le folositi).
Ca model, va fi folosit urmatorul document XML, stocat intr-un fisier „exemplu_simplexml.xml”:
<?xml version="1.0" encoding="utf-8"?>
<carti>
<titlu titlul="Titlu Carte" id="1">
<autor nume="Nume Autor" />
<text>Un text din carte</text>
<text>Un alt paragraf din carte</text>
<pret suma="0" />
</titlu>
<titlu titlul="Titlu a doua carte" id="2">
<autor nume="Nume Autor carte 2" />
<text>Un text din a doua carte</text>
<text>Un alt paragraf din cea dea doua carte</text>
<pret suma="00" />
</titlu>
</carti>
– Urmatorul script preia si afisaza cateva date din acest document XML (explicatiile necesare sunt in cod).
<?php
$obj = simplexml_load_file("exemplu_simplexml.xml"); // Calea si numele fisierului .xml
$titlu = $obj->titlu; // Preia toate elementele cu nume "titlu" (intr-o variabila tip array)
$text = $obj->titlu[0]->text; // Preia toate elementele cu nume "text" din primul element "titlu"
// Parcurge matricea cu $titlu si preia intr-un array elementele "autor" si "pret" din fiecare
for($i=0; $i<count($titlu); $i++) {
$autor[] = $titlu[$i]->autor;
$pret[] = $titlu[$i]->pret;
}
// Afiseaza valoarea atributului "nume" din primul element "autor"
echo $autor[0]['nume']. '<br>'; // Nume Autor
// Afiseaza valoarea atributului "suma" din al doilea element "pret"
echo $pret[1]['suma']. '<br>'; // 00
// Parcurge matricea $text (cu elementele "text" din primul "titlu")
// Afiseaza valoarea fiecaruia
for($i=0; $i<count($text); $i++) {
echo $text[$i]. ' - '; // Un text din carte - Un alt paragraf din carte
}
?>
– Testati singuri exemplul pentru a vedea rezultatul (folosind documentul XML „exemplu_simplexml.xml”).
2. Modificare document XML cu SimpleXML
Pe langa a prelua si folosi date dintr-un document XML, cu SimpleXML se poate si adauga date noi in acel document.
– Pentru a modifica valorile unor elemente sau atribute deja existente, se identifica acel element (sau atribut – cheie in matricea elementului) in sistemul ierarhic, si i-se atribue o noua valoare (vedeti metoda in exemplu de mai jos).
Daca studiati si testati urmatorul exemplu, puteti intelege cum se modifica document-ul XML (Scriptul va folosi acelasi fisier ca in primul exemplu, „exemplu_simplexml.xml”).
<?php
$obj = simplexml_load_file("exemplu_simplexml.xml"); // Calea si numele fisierului .xml
$titlu = $obj->titlu; // Preia toate elementele cu nume "titlu" (intr-o variabila tip array)
// Parcurge matricea cu $titlu si adauga, cu "addChild()" inca un element in fiecare, denumit "stoc", cu valoarea 1
for($i=0; $i<count($titlu); $i++) {
$titlu[$i]->addChild('stoc', 1);
}
// Modifica valoarea atributului 'nume' din elementul "autor" al primul element "titlu"
$titlu[0]->autor['nume'] = 'Nume Modificat';
// Folosind sistemul de lucru cu array, creaza inca un element "autor" (fiind al doilea cu acelasi nume, are indice [key] 1)
$titlu[0]->autor[1] = 'Alt autor';
// Tot cu sistemul de matrice, adauga in al doilea element "autor" inca o cheie 'atribut', cu o valoare, care vor deveni atributul elementului
$titlu[0]->autor[1]['atribut'] = 'Atribut_adaugat';
// Adauga datele XML intr-un sir
$xml_doc = $obj->asXML();
echo htmlentities($xml_doc); // Afiseaza documentul XML rezultat
?>