vineri, 8 aprilie 2011

PHP OOP - Utilizare clase si obiecte (1) (Part31)

O abordare importanta a activitatii de programare, care a devenit populara dupa 1990, este orientarea spre obiecte, OOP (Object Oriented Programming).
Orientarea spre obiecte a fost creata ca o modalitate de organizare mai eficienta a unor programe de simulare complexe, metoda care s-a dovedit utila in scrierea si utilizarea programelor interactive.
Principiul de baza al programarii orientate spre obiecte îl reprezinta incapsularea datelor, gruparea lor in module.
Un program care nu este orientat spre obiecte este organizat ca un set de functii si un set de variabile globale utilizate de acele functii. Orice functie poate opera folosind orice variabila globala.
Un program orientat spre obiecte combina una sau mai multe functii create de programator într-o unitate, cunoscuta sub numele de "clasa".
Programele orientate spre obiecte pot fi mai usor de înteles si modificat, deoarece interactiunile între clasele unui program orientat spre obiecte sunt relativ reduse ca numar. Astfel, un programator poate studia si întelege un program orientat spre obiecte abordând fiecare clasa în parte, nu toate clasele deodata.
Pe langa modatitatea de programare liniara (procedurala), invatata pana acum, PHP va permite sa creati si sa folositi clase si obiecte, respectiv proprietatile si metodele asociate acestora.
Aceasta lectie prezinta conceptele de baza ale orientarii spre obiecte in PHP, într-un mod general.

1. Clasele

O clasa este de fapt o structura care contine variabile (membrii) si functii (metode), Metodele sunt operatiile pe care membrii clasei le pot efectua.
Membrii si metodele declarate intr-o clasa apartin clasei respective si se acceseaza specificand numele clasei.
O clasa poate include o metoda speciala, numita "metoda constructor" sau "constructor". Aceasta este o functiei din clasa care are acelasi nume cu denumirea clasei.

Diferenta între clasa si obiect este importanta. Daca o clasa poate fi asimilata unui tip de date, un obiect poate fi echivalat cu o variabila sau cu o valoare avand un anumit tip de date. Practic, o clasa este o "fabrica" de obiecte, care produce obiecte cu aceeasi structura, avand proprietati si metode identice.



- Pe langa incapsularea datelor, o alta caracteristica importanta al POD este mostenirea
Mostenirea consta in aceea ca putem declara anumite clase ca fiind derivate din alte clase de baza. In cele mai multe situatii clasa derivata (numita si clasa copil) extinde, primeste functionalitatile clasei de baza (numita si clasa parinte). In acest fel se reduce foarte mult cantitatea de cod necesara.

2. Alcatuirea si instantierea unei clase

Definirea unei clase incepe cu un cuvantul cheie "class". Variabilele sau membrii clasei se specifica folosind cuvantul "var". Functiile sau metodele unei clase se declara specificand cuvantul "function" . Structura general de alcatuire a unei clase este urmatoarea:

class nume_claca {
    var membru1;
    var membru2;
    .................
    function nume_functie(); {
        function metoda1();
        function metoda2();
        .................
    }
}

Pentru a intelege mai bine modalitatea de definire a unei clase în PHP, consideram urmatorul exemplu in care alcatuim o clasa simpla denumita "ContBanca":

<?php

// Definirea clasei

class ContBanca {
    var $sold = 0;             // Membru clasei
    // Definirea primei metode a clasei
    function c_depozit($suma) {
        $this->sold = $this->sold + $suma;
    }
    // Definirea celei dea doua metode a clasei
    function obtine_sold() {
        return $this->sold;
    }
}
?>

- Clasa "ContBanca" are un singr membru, "$sold" si doua metode: "c_depozit()" si "obtine_sold()".
- Membru (variabila) "$sold" este definita de o instructiune "var". Clasa "ContBanca" atribuie variabilei "$sold" valoarea initiala zero ( Nu este necesara atribuirea unei valori initiale unei proprietati, dar astfel programele devin mai simple si mai usor de citit).
- Cele doua metodele (functii) sunt definite folosind cuvântul cheie "function". (Diferenta dintre metode si functii este legata de amplasarea acestora, pentru a se face deosebirea; metodele sunt definite în interiorul claselor, în timp ce functiile sunt definite în exteriorul acestora).
Un aspect interesant al metodelor consta în modalitatea în care acestea obtin accesul la variabila, folosend sintaxa "$this->" (aceasta are o semnificatie similara cu a pronumelui posesiv din limba româna (al meu)). Când o metoda face o referire de forma "$this->sold", se considera ca face trimitere la membru "$sold" a obiectului curent, aici efectul este similar cu acela al expresiei "sold-ul mea".

Instantierea unei clase se face prin operatorul "new", avand urmatoarea forma generala:

$nume_variabila = new nume_clasa();

Variabila "$nume_variabila" contine o referinta la clasa "nume_clasa". In continuare se apeleaza metodele clasei respective, asta se face prin operatorul de referinta "->" ca mai jos:

$nume_variabila->Metoda1();

Variabila apeleaza metoda cu numele "Medoda1()", care apartine clasei "nume_clasa".
Stergerea instantelor unei clase se face simplu prin apelarea functiei:

unset($nume_variabila)

Dupa aceasta stergere, orice apel de genul "$nume_variabila->Metoda1();" va fi semnalat ca eroare.
Iata un exemplu concret de Instantiere in care folosim clasa "ContBanca", definita mai sus.

<?php
// Definirea clasei

class ContBanca {
    var $sold = 0;             // Membru clasei

    // Definirea primei metode a clasei
    function c_depozit($suma) {
        $this->sold = $this->sold + $suma;
    }
    // Definirea celei dea doua metode a clasei
    function obtine_sold() {
        return $this->sold;
    }
}
// Instantierea clasei (setarea obiectului)
$cont = new ContBanca();
// Apelarea metodelor din obiectul setat
$cont->c_depozit(90);
echo "<br /> Soldul este : ". $cont->obtine_sold();
?>

- Prima instructiune, dupa crearea clasei, seteaza (instantiaza) un obiect "ContBanca" folosind operatorul "new" si stocheaza referinta la acest obiect în variabila "$cont", care va fi utilizata ulterior pentru a obtine acces la metodele obiectului.
- A doua instructiune foloseste variabila "$cont", (care face referire la obiectul "ContBanca" creat de prima instructiune). Operatorul "->" arata ca PHP trebuie sa apeleze metoda "c_depozit()" asupra obiectului desemnat de variabila "$cont".
Astfel, prin a doua instructiune se va executa metoda "c_depozit()", careia ii este transmis argumentul 90. Dupa cum este definita, metoda "c_depozit", aceasta incrementeaza valoarea membrului "$sold" cu valoarea argumentului din paranteze, "$suma" (adica aici 90).
- Cea de-a treia instructiune invoca metoda "obtine_sold()", care returneaza valoarea membrului "$sold". Instructiunea afiseaza valoarea returnata prin intermediul unei instructiuni "echo", afisand "Soldul este : 90".

3. Definirea unei metode constructor

Metoda constructor este o functie din interiorul clasei care are aceeasi denumire cu numele clasei.
Pentru ca o clasa sa fie eficienta, ar trebui sa aibe mai multi membri.
De exemplu, clasa "ContBanca", pe langa membrul "$sold", ar necesita membrii care sa defineasca numele si id-ul posesorului.
Iata o noua versiune a clasei, care include trei membri si o metoda constructor:

<?php
// Definirea clasei

class ContBanca {
    // Membri clasei
    var $cont_id;
    var $nume_posesor;
    var $sold = 0;

    // Definirea metodei constructor
    function ContBanca($id, $nume, $suma) {
        $this->cont_id = $id;
        $this->nume_posesor = $nume;
        $this->sold = $suma;
    }

    // Definirea celei dea doua metode a clasei
    function c_depozit($suma) {
        $this->sold = $this->sold + $suma;
        return $this->sold;
    }
}
?>

- Constructorul este "function ContBanca()", asa cum se observa, are acelasi nume ca al clasei. Deosebirea fata de ceilalti membri este ca la invocarea operatorului "new", pentru setarea obiectului, PHP va apela automat si aceasta functie din clasa.
Argumentele constructorului sunt folosite pentru a stabili valorile initiale ale membrilor noului obiect, "$id", "$nume" si "$suma".
Iata cum s-ar putea folosi noua clasa, adaugam codul de mai jos dupa datele de definire a clasei, pe care nu le mai repetam:

<?php
// Aici sunt adaugate datele pentru definirea clasei

// Setarea (instantierea) obiectului "ContBanca"
$cont = new ContBanca(8, "Plo Mar", 100);
echo "<br /> Contul $cont->cont_id apartine lui $cont->nume_posesor";
// Apelarea celei dea doua metode
$cont->c_depozit(90);
echo "<br /> Soldul este $cont->sold";
?>

- Instructiunea "$cont = new ContBanca(8, "Plo Mar", 100);" obtine accesul la membrii obiectului în mod direct, prin "constructorul" care are acelasi nume cu al clasei, transferandu-le valorile "8", "Plo Mar" si "100"
- Datele de iesire ale acestui exemplu sunt urmatoarele:


Contul 8 apartine lui Plo Mar
Soldul este 190

4. Utilizarea mostenirii

Asa cum s-a explicat la inceput, un avantaj al programarii orientate spre obiecte este facilitatea cunoscuta sub numele de mostenire.
Pentru a intelege cum functioneaza, iata un exemplu care prezinta modul de derivare a unei clase "ContCurent" din clasa de baza "ContBancar", definita anterior si pe care o salvam intr-un fisier extern "contbanca.php":

<?php
include("contbanca.php");             // Include clasa parinte (sau poate fi scrisa aici)

// Definirea clasei copil
class ContCurent extends ContBanca {
    var $cec_nr;             // Membru clasei copil

    // Metoda constructor a clasei copil
    function ContCurent($id, $nume, $suma, $cecnr) {
        $this->cont_id = $id;
        $this->nume_posesor = $nume;
        $this->sold = $suma;
        $this->cec_nr = $cecnr;
    }

    // A doua metoda a clasei copil
    function primire_cec($cecnr, $suma) {
        $this->sold = $this->sold - $suma;
    }

    // A treia metoda a clasei copil
    function obtine_sold() {
        return $this->sold;
    }
}
?>

- Exemplul foloseste o instructiune "include" pentru a obtine accesul la definitia clasei "ContBanca". (sau puteti scrie direct aceasta clasa in locul "include").
- Cuvântul cheie "extends" stabileste identitatea clasei "ContCurent" ca fiind derivata (copil) a clasei "ContBanca".
- Clasa derivata defineste un membru, "$cec_nr", de asemenea, defineste un constructor si alte doua metode, "primire_cec()" si "obtine_sold()".
Important este faptul ca aceasta clasa mai include si membrii definiti în clasa de baza (parinte): "$cont_id", "$nume_posesor" si "$sold", in plus va mosteni si metoda "c_depozit()". Constructorul clasei copil atribuie valori membrilor mosteniti, dar si membrilor noi definiti în clasa copil.
Clasa derivata (copil) se foloseste ca orice clasa.
Dupa ce adaugam datele de definire a claselor parinte si copil prezentate mai sus, creem un obiect "ContCurent" care face referire la aceasta clasa copil, ca in exempll urmator.

<?php
// Aici sunt adaugate datele pentru clasa parinte si clasa derivata (copil)
// Setarea (instantierea) obiectului "ContCurent"
$cont = new ContCurent(8, "Plo Mar", 100, 11);
$cont->primire_cec(11, 150);             // Apeleaza metoda creata in clasa copil
$cont->c_depozit(250);             // Apeleaza metoda mostenita
echo "<br /> Soldul este". $cont->obtine_sold();
?>
- Observati ca metoda "c_depozit()", care este definita în clasa de baza, este invocata ca si cum ar fi fost definita în clasa derivata; metodele mostenite se apeleaza la fel ca cele create in clasa copil.
- Dupa ce veti include in acelasi fisier php clasa parinte, clasa copil si instantierea de mai sus, rezultatul afisat dupa executia acestui fisier va fi: Soldul este 200".