VII. Clase si obiecte
29.05.2008
Pe parcursul acestui tutorial, vei putea citi despre capacitatile PHP in legatura cu implementarea obiectelor (atat in PHP 4 cat si in PHP 5) si vei putea urmari diverse exemple si explicatii ce ilustreaza utilizarea lor.
9884 afisari 7 Rating (13 voturi) 20 min

Clase si obiecte
Acum ca stii sa creezi functii in PHP, probabil ca ti-ai petrecut ultimele zile inspectand propriile aplicatii si inlocuind anumite fragmente de cod cu functii. Totusi, ar trebui sa stii ca functiile reprezinta doar varful icebergului. Sub ele, se ascunde un acronim de trei litere care inspira frica in randul programatorilor incepatori.

POO.
Daca lucrezi de ceva timp in PHP, probabil ca ai mai auzit termenul de POO – inseamna Programare Orientata pe Obiecte. In POO, scriptul PHP lucreaza cu entitati denumite „obiecte” pentru construi functionalitatea necesara programului tau. Spre deosebire de PHP 4, PHP 5 ofera suport extins pentru POO, aducand obiectele PHP la standardele impuse de catre principiile POO si oferind programatorilor noi facilitati.

Pe parcursul acestui tutorial, vei putea citi despre capacitatile PHP in legatura cu implementarea obiectelor (atat in PHP 4 cat si in PHP 5) si vei putea urmari diverse exemple si explicatii ce ilustreaza utilizarea lor. Vom acoperi principiile de baza – clasa, obiecte, atribute si metode – insotite de cateva concepte mai avansate – constructori, destructori, specificatori de acces, proprietati si clase mostenite. Chiar daca programarea orientata pe obiecte este un subiect nou pentru tine, nu ai de ce sa-ti faci griji – obiectele in PHP sunt usor de folosit si de inteles, si te vor ajuta sa iti organizezi cat mai bine munca.

Clase in PHP
Inainte de a trece mai departe, trebuie sa ai o idee clara despre conceptele pe care POO le presupune.

In PHP, o clasa reprezinta un set de instructiuni care indeplinesc o anumita sarcina. Implementarea unei clase contine atat variabile, cat si functii, ea reprezentand un sablon (template) cu ajutorul caruia pot fi create instante specifice.

Aceste instante specifice ale unei clase poarta numele de obiecte. Fiecare obiect are o serie de caracteristici, sau proprietati, si anumite functii predefinite – metode. Aceste proprietati si metode ale unui obiect corespund variabilelor si functiilor din definitia clasei.

Odata ce ai creat o clasa, poti defini oricate instante ale acesteia. Fiecare dintre aceste instante reprezinta un obiect independent, ce poate fi manipulat fara ca celelalte obiecte sa fie afectate in vreun fel. Aceasta indepedenta a obiectelor devine foarte utila atunci cand trebuie sa lucrezi cu doua instante in acelasi timp – de exemplu, doua conexiuni simultane la o baza de date, sau doua interogari (query), sau doua carucioare de cumparaturi ale unui magazin online.

Clasele te ajuta si in ceea ce priveste modularitatea codului – poti defini o clasa intr-un fisier separat, incluzandu-l apoi in scripturile care folosesc aceasta clasa. Aceasta modalitate de implementare simplifica modificarile ulterioare pentru ca, in cazul in care vei dori sa adaugi noi functionalitati obiectelor tale, vei avea de modificat un singur fisier.

Ca sa intelegi mai bine cele de mai sus, sa luam ca exemplu un animal, cum ar fi un urs, si sa incercam sa il reprezentam ca un obiect.

Orice urs are anumite caracteristici – varsta, greutate, sex – care sunt echivalente cu proprietatile unui obiect. In plus, fiecare urs are anumite activitati – mananca, doarme, merge, alearga si hiberneaza – acestea reprezentand metodele unui obiect.

Deoarece toti ursii au in comun anumite caracteristici, putem crea un template Urs(), care defineste caracteristicile de baza si abilitatile fiecarui urs de pe planeta. Aceasta clasa Urs() poate fi utilizata pentru a crea un obiect $urs, proprietatile individuale ale unui Urs putand fi manipulate independent fata de cele ale altor obiecte de acelasi tip.

In PHP 5, clasa Urs ar arata in felul urmator:

<?php 
// PHP 5 
// definitia clasei
class Urs { 
    // definitia proprietatilor
    public $nume; 
    public $greutate; 
    public $varsta; 
    public $sex; 
    public $culoare; 
    // definitia metodelor
    public function mananca() { 
        echo $this->nume." mananca... "; 
    } 
    public function alearga() { 
        echo $this->nume." alearga... "; 
    } 
    public function vaneaza() { 
        echo $this->nume." vaneaza... "; 
    } 
 
    public function doarme() { 
        echo $this->nume." doarme... "; 
    } 
} 
?>

Avand aceasta clasa, putem crea oricati ursi vrem:

<?php 
// primul urs 
$daddy = new Urs; 
// sa-i dam un nume 
$daddy->nume = "Tata urs"; 
//  cati ani are 
$daddy->varsta = 8; 
// ce sex este 
$daddy->sex = "mascul"; 
// culoarea blanii 
$daddy->culoare = "negru"; 
// cat cantareste 
$daddy->greutate = 300; 
 
// cel de-al doilea urs 
$mommy = new Urs; 
$mommy->nume = "Mama urs"; 
$mommy->varsta = 7; 
$mommy->sex = "femela"; 
$mommy->culoare = "negru"; 
$mommy->greutate = 310; 
 
// cel de-al treilea urs 
$baby = new Urs; 
$baby->nume = "Puiul urs"; 
$baby->varsta = 1; 
$baby->sex = "mascul"; 
$baby->culoare = "negru"; 
$baby->greutate = 180; 
 
// o seara placuta pentru familia Urs 
// ursul tata vaneaza si aduce prada acasa 
$daddy->vaneaza(); 
 
// ursul mama mananca 
$mommy->mananca(); 
// la fel si puiul 
$baby->mananca(); 
 
// ursul mama doarme
$mommy->doarme(); 
// la fel si tatal 
$daddy-> doarme (); 
 
// puiul mananca in continuare 
$baby->mananca(); 
?>

Dupa cum se poate observa din exemplul de mai sus, atunci cand sunt definite noi obiecte, metodele si proprietatile lor pot fi accesate in mod independent pentru fiecare obiect.

Definitia unei clase
Dupa ce am explicat conceptele de baza ale POO, sa vedem in continuare cum anume se defineste o clasa:

<?php 
// PHP 5 
// definitia clasei 
class Urs { 
    // defineste proprietatile public
    public $nume; 
    public $varsta; 
    // alte proprietati 
    // defineste o metoda public
    public function mananca() { 
        echo $this->nume." mananca... "; 
        // mai mult cod 
    } 
    // alte metode  
} 
?>

Orice definitie a unei clase incepe prin cuvantul cheie class, urmat de numele clasei. Acesta poate fi orice sir de caractere, in afara unui cuvant rezervat PHP, fiind urmat de o pereche de acolade ce include variabilele si functiile clasei.

PHP5 introduce un nou concept care nu este disponibil in PHP4: specificatorii de acces. Acestia controleaza gradul in care proprietatile obiectelor si metodele lor pot fi manipulate din exteriorul clasei, avand un rol important in ceea ce priveste securitatea claselor. Exista trei specificatori de acces, de la cel mai permisiv la cel mai restrictiv: public, private si protected. In definitia unei clase poti marca gradul de vizibilitate al unei proprietati sau metode precedand-o cu unul dintre cele trei cuvinte cheie.

In mod implicit, proprietatile si metodele unei clase sunt public. Aceasta inseamna ca ele pot fi accesate direct si manipulate de catre un script care nu se afla in interiorul clasei. Daca nu doresti acest lucru, il poti impiedica utilizand specificatorii de acces private sau protected, in functie de gradul de control pe care vrei sa il detina un script exterior asupra obiectelor tale. Deoarece in PHP4 nu exista specificatori de acces, definitia clasei de mai sus nu va functiona in PHP4. In schimb, ea poate fi inlocuita cu urmatorul cod:

<?php 
// PHP 4 
// definitia clasei 
class Urs { 
    // definitia proprietatilor 
    var $nume; 
    var $greutate; 
    var $varsta; 
    var $sex; 
    var $culoare; 
    // definitia metodelor 
    function mananca() { 
        echo $this->nume." mananca... "; 
    } 
    function alearga() { 
        echo $this->nume." alearga... "; 
    } 
    function vaneaza() { 
        echo $this->nume." vaneaza... "; 
    } 
    function doarme() { 
        echo $this->nume." doarme... "; 
    } 
} 
?>

Avand in fata exemplul de mai sus, poti deduce usor faptul ca in PHP4 toate proprietatile si metodele unui obiect sunt public.

Pentru a crea o noua instanta a clasei de mai sus, foloseste cuvantul cheie new:

<?php 
$tata_urs = new Urs; 
?>

Codul din exemplul anterior s-ar putea citi ca : „creeaza un nou obiect de tipul Urs si salveaza-l in variabila $tata_urs”.

Acum poti accesa toate proprietatile si functiile clasei Urs folosind aceasta variabila. De exemplu, codul:

<?php 
$tata_urs->nume = "Tata urs"; 
?>

s-ar traduce ca „atribuie valoarea „Tata urs” variabilei $nume a instantei $tata_urs a clasei Urs”, in timp ce declaratia:

<?php 
$tata_urs->doarme(); 
?>

inseamna „executa functia doarme() pentru instanta $tata_urs a clasei Urs”.

Poti observa ca simbolul „->” este folosit pentru a apela diferitele proprietati si metode ale obiectelor, caracterul „$” fiind omis atunci cand accesam variabilele unui obiect.

Cuvantul cheie „this”
Daca vrei sa accesezi functiile si variabilele unei clase chiar in cadrul acesteia, atat PHP4, cat si PHP5, iti pun la dispozitie cuvantul cheie $this, care este folosit ca o referinta la instanta curenta. Pentru a vedea cum functioneaza acesta, sa modificam functia mananca() pentru a primi ca parametru un numar de unitati de mancare care sunt adunate la greutatea unui urs:

<?php 
// PHP 5 
// definitia clasei 
class Urs { 
    // definitia proprietatilor 
    public $nume; 
    public $greutate; 
    // definitia  metodelor
    public function mananca($unitati) { 
        echo $this->nume." mananca ".$unitati." unitati de mancare... "; 
        $this->greutate += $unitati; 
    } 
} 
?>

In acest caz, prefixul $this indica faptul ca variabila ce urmeaza a fi modificata a fost definita ca proprietate a clasei. Acest lucru poate fi exprimat ca: „pentru acest obiect, aduna argumentul functiei mananca() la variabila $greutate”. In concluzie, cuvantul cheie $this iti ofera o metoda facila de a accesa variabilele si functiile „locale” ale clasei.

Iata un exemplu care ilustreaza functionarea sa:

<?php 
// creeaza instanta 
$pui = new Urs; 
$pui->nume = "Puiul urs"; 
$pui->greutate = 1000; 
// creeaza o alta instanta 
// cu valori independente pentru fiecare proprietate
$frate = new Urs; 
$frate->nume = "Fratele puiului"; 
$frate->greutate = 1000; 
// afiseaza proprietatile 
echo $pui->nume." cantareste ".$pui->greutate." unitati "; 
echo $frate->nume." cantareste ".$frate->greutate." unitati "; 
// apeleaza functia mananca() 
$pui->mananca(100); 
$pui->mananca(50); 
$frate->mananca(11); 
// afiseaza noile valori 
echo $pui->nume." cantareste acum ".$pui->greutate." unitati "; 
echo $frate->nume." cantareste acum ".$frate->greutate." unitati ";
?>

Codul de mai sus va afisa:

Puiul urs cantareste 1000 unitati
Fratele puiului cantareste 1000 unitati
Puiul urs mananca 100 unitati de mancare...
Puiul urs mananca 50 unitati de mancare...
Fratele puiului mananca 11 unitati de mancare...
Puiul urs cantareste acum 1150 unitati
Fratele puiului cantareste acum 1011 unitati

Constructori
In PHP ai posibilitatea de a executa o metoda a unei clase atunci cand este creata o noua instanta a acesteia. Aceasta metoda poarta denumirea de constructor. Pentru a o utiliza, definitia clasei tale in PHP5 trebuie sa contina o functie speciala, __construct().

De exemplu, daca vrei ca toti puii de urs nou-nascuti sa aiba blana maro si cantareasca 100 de unitati, poti folosi codul de mai jos:

<?php 
// PHP 5 
// definitia clasei 
class Urs { 
    // definitia proprietatilor 
    public $nume; 
    public $greutate; 
    public $varsta; 
    public $culoare; 
    // constructor 
    public function __construct() { 
        $this->varsta = 0; 
        $this->greutate = 100; 
        $this->culoare = "maro"; 
    } 
     // definitia metodelor 
} 
?>

In PHP4, constructorul trebuie sa aiba acelasi nume ca si clasa. Iata codul echivalent pentru PHP4:

<?php 
// PHP 4 
// definitia clasei 
class Urs { 
    // definitia proprietatilor 
    var $nume; 
    var $greutate; 
    var $varsta; 
    var $culoare; 
    // constructor 
    function Urs() { 
        $this->varsta = 0; 
        $this->greutate = 100; 
        $this->culoare = "maro"; 
    } 
    // definitia metodelor 
} 
?>

Sa cream o noua instanta a clasei:

<?php 
// creeaza instanta 
$pui = new Urs; 
$pui->nume = "Puiul urs"; 
echo $pui->nume." are culoarea ".$pui->culoare." si 
cantareste ".$pui->greutate." unitati la nastere"; 
?>

Constructorul va initializa in mod automat proprietatile culoare si greutate pentru fiecare obiect de tipul Urs care este creat. In consecinta, scriptul de mai sus la afisa:

Puiul urs are culoarea maro si cantareste 100 unitati la nastere

Restrictionarea accesului
Dupa cum am precizat mai sus, PHP5 permite marcarea proprietatilor si metodelor unei clase ca private, ceea ce inseamna ca ele nu pot fi modificate sau afisate in afara definitiei clasei respective. Acest lucru este util a impiedica manipularea proprietatilor unei clase de catre o instanta a acesteia. Sa consideram urmatorul exemplu, care ilustreaza acest lucru prin adaugarea unei noi variabile private $_ultimeleUnitatiConsumate in clasa Urs():

<?php 
// PHP 5 
// definitia clasei 
class Urs { 
    // definitia proprietatilor 
    public $nume; 
    public $greutate; 
    public $varsta; 
    private $_ultimeleUnitatiConsumate; 
    // constructor 
    public function __construct() { 
        $this->varsta = 0; 
        $this->greutate = 100; 
        $this->_ultimeleUnitatiConsumate = 0; 
    } 
     // definitia metodelor 
    public function mananca($unitati) { 
        echo $this->nume." mananca ".$unitati." unitati de mancare... "; 
        $this->greutate += $unitati; 
        $this->_ultimeleUnitatiConsumate = $unitati; 
    } 
    public function afiseazaUltimaMasa() { 
        echo "Unitatile consumate la ultima masa 
        au fost ".$this->_ultimeleUnitatiConsumate." "; 
    } 
} 
?>

Deoarece variabila $_ultimeleUnitatiConsumate este declarata ca private, orice tentativa de a o modifica va genera o eroare. Iata un exemplu:

<?php 
$bob = new Urs; 
$bob->nume = "Ursul Bobby"; 
$bob->mananca(100); 
$bob->mananca(200); 
echo $bob-> afiseazaUltimaMasa(); 
// urmatoarea linie va genera o eroare 
$bob->_ultimeleUnitatiConsumate = 1000; 
?>

In mod similar, si metodele unei clase pot fi declarate ca private, ceea ce inseamna ca ele nu pot fi apelate decat din interiorul clasei respective.

Mostenirea unei clase
Doua dintre principalele avantaje ale POO, fie PHP4, fie PHP5, sunt extensibilitatea si mostenirea. Aceasta inseamna ca poti crea o clasa noua dintr-o clasa deja existenta, adaugand noi proprietati si metode, si apoi poti defini noi instante ale acestei clase. Aceste obiecte vor avea toate facilitatile mostenite de la clasa parinte, impreuna cu noile proprietati si metode ale clasei copil.

Pentru a ilustra acest concept, sa consideram clasa UrsPolar() care mosteneste clasa Urs() si defineste o noua metoda:

<?php 
// PHP 5 
// definitia clasei
class Urs { 
    // definitia proprietatilor
    public $nume; 
    public $greutate; 
    public $varsta; 
    public $sex; 
    public $culoare; 
    // constructor 
    public function __construct() { 
        $this->varsta = 0; 
        $this->greutate = 100; 
    }
    // definitia metodelor
    public function mananca($unitati) { 
        echo $this->nume." mananca ".$unitati." unitati 
        de mancare... "; 
        $this->greutate += $unitati; 
    }
    public function alearga() { 
        echo $this->nume." alearga... "; 
    } 
    public function vaneaza() { 
        echo $this->nume." vaneaza... "; 
    } 
    public function doarme() { 
        echo $this->nume." doarme... "; 
    } 
} 
// extindem definitia clasei Urs 
class UrsPolar extends Urs { 
    // constructor 
    public function __construct() { 
        parent::__construct(); 
        $this->culoare = "alb"; 
        $this->greutate = 600; 
    } 
    // definitia metodelor 
    public function inoata() { 
        echo $this->nume." inoata... "; 
    } 
} 
?>

Cuvantul cheie extends este utilizat pentru a crea o clasa copil dintr-o clasa parinte. In acest mod, toate functiile si variabilele din clasa parinte sunt disponibile in clasa copil, dupa cum se poate observa in exemplul de mai jos:

<?php 
// creeaza o noua instanta a clasei Urs() 
$tom = new Urs; 
$tom->nume = "Ursul Tommy"; 
// creeaza o noua instanta a clasei UrsPolar() 
$bob = new UrsPolar; 
$bob->nume = "Ursul Bobby"; 
/* $bob poate apela toate metodele claselor Urs() si UrsPolar() */
$bob->alearga(); 
$bob->vaneaza(); 
$bob->inoata(); 
// $tom poate apela doar metodele clasei Urs() 
$tom->alearga(); 
$tom->vaneaza(); 
$tom->inoata(); 
?>

In acest caz, apelul final $tom->inoata() va genera o eroare deoarece clasa Urs() nu contine nici o metoda inoata(). In acelasi timp, instructiunile $bob->alearga() si $bob->vaneaza() vor fi executate cu succes deoarece clasa UrsPolar() mosteneste toate metodele si proprietatile clasei Urs().

In exemplul anterior, poti observa cum a fost apelat constructorul clasei parinte din constructorul clasei UrsPolar(). In general, acest lucru este util pentru a ne asigura ca toate initializarile din clasa parinte au fost efectuate inaintea altor initializari in constructorul clasei copil. Daca o clasa mostenita nu are constructor, va fi apelat in mod implicit constructorul clasei pe care o mosteneste.

Iata definitia clasei UrsPolar in PHP4:

<?php 
// PHP 4 
// UrsPolar extinde definitia clasei Urs 
class UrsPolar extends Urs { 
    // constructor 
    function UrsPolar() { 
        parent::Urs(); 
        $this->culoare = "alb"; 
        $this->greutate = 600; 
    } 
    // definitia metodelor 
    function inoata() { 
        echo $this->nume." inoata... "; 
    } 
} 
?>

Pentru a impiedica mostenirea unei clase sau a unor metode ale sale, foloseste cuvantul cheie final inaintea numelui clasei sau al metodei (aceasta este o facilitate a PHP5 care nu este disponibila in versiunile PHP mai vechi). Iata un exemplu care modifica definitia clasei Urs() astfel incat aceasta sa nu mai poata fi mostenita:

<?php 
// PHP 5 
// definitia clasei 
final class Urs { 
    // definitia proprietatilor 
 
    // definitia metodelor
} 
/* extinderea definitiei clasei va genera o eroare 
   deoarece clasa Urs nu poate fi mostenita */
class UrsPolar extends Urs { 
   // definitia metodelor 
} 
// crearea unei instante a clasei UrsPolar() 
// apelul va esua deoarece clasa Urs nu poate fi mostenita  
$bob = new UrsPolar; 
$bob->nume = "Ursul Bobby"; 
echo $bob->greutate; 
?>
Copyright © 2008-2010 E-LEARN.ro. Toate drepturile rezervate. Conceput si realizat de Neokinetics Software.