PHP folosind OOP - Mostenirea pe intelesul tuturor

Post Title

Intr-un articol precedent am discutat despre incapsulare, fiind modul prin care protejam proprietatile ( chiar si metodele ) unui obiect, declarand o vizibilitate diferita de public, interactionarea cu acestea fiind facuta prin intermediul metodelor.Astazi, vom discuta despre mostenire, un alt concept fundamental.

Mostenirea este un mecanism de refolosirea a codului, oferindu-ne posibilitatea de a declara o clasa, numita clasa parinte, de la care, alte clase, numite clase copil, sa mosteneasca proprietatile si metodele ce au vizibilitatea diferita de private.Astfel, daca in mai multe clase avem portiuni de cod ce se repeta, putem muta codul din aceste intr-o clasa de la care toate aceste clasa sa mosteneasca.

<?php

class ParentClass
{
    public $name = 'Parent';

    public function saySomething()
    {
        return 'I am of type ParentClass';
    }
}

class ChildClass extends ParentClass
{

}

$child = new ChildClass();

echo $child->saySomething(); // I am of type ParentClass

echo $child->name; // Parent

Pentru ca o clasa sa poata mosteni, dupa numele acesteia trebuie sa adaugam cuvantul predefinit extends urmat de numele clasei de la care se mosteneste.Dupa cum putem observa in exemplul de mai sus, clasa ChildClass mosteneste de la clasa ParentClass, astfel clasa ChildClass poate folosi toate metodele si proprietatile clasei ParentClass ce au vizibilitatea diferita de private.

class ChildClass extends ParentClass
{
    public function saySomethingMore()
    {
        this->name = 'Child';

        return $this->saySomething() . ' and of type ChildClass';
    }
}

$child = new ChildClass();

echo $child->saySomethingMore(); // I am of type ParentClass and of type ChildClass

echo $child->name; // Child

Dupa cum putem observa, in interiorul unei clase ce mosteneste, putem folosi metodele si proprietatile clasei parinte ca si cum ar face parte din clasa ce mosteneste.

Putem rescrie proprietatile/metodele clasei parinte?

Desigur ca putem face acest lucru, pur si simplu redeclaram aceste metodele/proprietatile.

class ChildClass extends ParentClass
{
    public function saySomething()
    {
        return 'I am of type ChildClass';
    }
}

$child = new ChildClass();

echo $child->saySomething(); // I am of type ChildClass

Putem folosi metodele rescrise din clasa parinte?

Desigur, putem face si acest lucru, singura diferenta fiind modul in care accesam proprietatile/metodele rescrise.Trebuie sa folosim urmatoarea sintaxa parent::numeMethods().

<?php
class ChildClass extends ParentClass
{
    public function saySomething()
    {
        return parent::saySomething() . ' and of type ChildClass';
    }
}

$child = new ChildClass();

echo $child->saySomething(); // I am of type ParentClass and of type ChildClass

Trebuie sa folosim o aceeasi sintaxa daca dorim sa folosim metodele magice rescrise.

<?php

class ParentClass
{
    public $name;

    public function __construct()
    {
        $this->name = 'Parent';
    }
}

class ChildClass extends ParentClass
{
    // declaram constructor propriu clasei copil
    // astfel rescriem constructorul clasei parinte
    public function __construct()
    {
        // accesam constructorul clasei parinte
        parent::__construct();
    }
}

$child = new ChildClass();

echo $child->name; // Parent

Ce sunt clasele si metodele finale?

PHP 5 a introdus posibilitatea de a declara o clasa folosind cuvantul predefinit final, ceea ce face ca acea clasa sa nu poate fi exista/mostenita.

<?php

final class ParentClass
{

}

class ChildClass extends ParentClass
{

}

Codul de mai sus va afisa urmatoarea eroare: Fatal error: Class ChildClass may not inherit from final class (ParentClass)

De asemenea, PHP a introdus acelasi lucru pentru metode, astfel, atunci cand o metoda este declarata folosind prefixul final, aceasta nu poate fi mostenita.

Poate o clasa mosteni de la mai multe clase?

Nu, acest lucru nu este posibil, o clasa poate extinde doar de la o singura clasa, nu putem face:

class FirstParentClass {}

class SecondParentClass {}

// incorect
class Child extends FirstParentClass, SecondParentClass {} 

Cand putem folosi acest mecansim de refolosire a codului?

Ei bine, aceasta este marea intrebare! Stim ca atunci cand intalnim in mai multe clase aceleasi portiuni de cod, acest lucru ne poate indica ca putem folosi mostenirea, insa asta nu este tot, da, mai este ceva! Aceste clase trebuie sa aiba un punct comun, trebuie sa fie reprezentarea a ceva, sa fie de un anumit tip.

Cel mai bine, putem intelege pe baza unui exemplu practic.Sa prespunem ca lucram la o aplicatie unde avem utilizatori ce sunt autori, fiind cei ce creaza articole, dar si utilizatori editori, fiind cei ce verifica si aranjeaza articolele, astfel putem avea:

Author.php

<?php

class Author
{
    protected $username;

    public function setUsername($username)
    {
        $this->username = $username;
    }

    public function getUsername()
    {
        return $this->username;
    }
}

Editor.php

<?php

class Editor
{
    protected $username;

    public function setUsername($username)
    {
        $this->username = $username;
    }

    public function getUsername()
    {
        return $this->username;
    }

}

Dupa cum putem observa, in ambele clase gasim portiuni similare de cod, fiind prirmul indiciu spre folosirea mostenirii, insa mai este ceva, da, ambele clase au un punct comn, exista o relatie intre ele, reprezinta utilizatorul, astfel, putem spune ca sunt de tipul utilizator (user).

Vom crea clasa User.php, si in aceasta clasa vom muta codul ce se repeta din ambele clase.

User.php

<?php

class User
{
    protected $username;

    public function setUsername($username)
    {
        $this->username = $username;
    }

    public function getUsername()
    {
        return $this->username;
    }
}

Clasele Author.php si Editor.php vor mosteni de la aceasta clasa.

Author.php

<?php

class Author extends User
{

}

Editor.php

<?php

class Editor extends User
{

}

Atat autorul cat si editorul sunt utilizatori in aplicatia noastra, punctul lor comun.

In concluzie, putem aplica mostenirea atunci cand:

  • in mai multe clase gasim portiuni de cod similare
  • intre aceste clase exista o relatie, un punct comun, prin care putem spune ca aceste clase sunt de un anumit tip.

Bonus :))

Atunci cand declaram argumentele unei functii/metode si specificam si tipul de date pe care aceste argumente il pot avea, in cazul obiectelor, putem substitui obiectele unei clase parinte, cu cele ale unei clase copil:

<?php

class ParentClass
{
    public function saySomething()
    {
        return 'I am of type ParentClass';
    }
}

class ChildClass extends ParentClass
{
    public function saySomethingMore()
    {
        return 'I am of type ChildClass';
    }
}

class TestClass
{
    protected $service;

    public function __construct(ParentClass $service)
    {
        $this->service= $service;
    }

    public function saySomething()
    {
        return $this->service->saySomething();
    }
}

$childClass = new ChildClass();
$test = new TestClass($childClass);

echo $test->saySomething(); // I am of type ParentClass

Observam ca in constructorul clasei TestClass am specificat ca argumentul $service sa fie o instanta a clasei ParentClass, insa atunci cand am instantiat clasa TestClass, am introdus ca parametru in constructor o instanta a clasei ChildClass, si totusi, a functionat. Acest lucru se intampla deoarece clasa ChildClass a extins clasa ParentClass.

Bonus 2 :))

PHP a mai introdus inca un mecansim interesant de reutilizare a codului prin folosirea de traits, astfel putem trece de limitarea de a mosteni doar de la o singura clasa.Acest mecansim este folosit impreuna cu mostenirea, de exemplu, atunci cand avem, sa zicem, 10 clase care deja extind de la o clasa parinte, insa in 3 dintre aceste clase gasim cod ce se repeta doar la aceste clase, nu este o solutie buna sa mutam si acest cod in clasa parinte, putem crea un trait.

The end...

In continuare, trebuie sa mai discutam si despre clasele abstracte, fiind create special cu scopul de a fi folosite cu acest mecansim de mostenire ( clasele abstracte nu pot fi instantiate, iar in interiorul lor putem declara pe langa ceea ce putem declara intr-o clasa normala, metode abstracte, cu alte cuvinte, metode ce prezinta doar semnatura, nu si implementarea, corpul ).

Sper ca acest articol sa va ajute cat mai mult!

Autor articol
David: Why do you want to leave me? Why? I'm sorry I'm not real! If you let me, I'll be so real for you!

Acest articol nu este comentat, fii primul care o face

Trebuie sa fii logat sa poti lasa un comentariu Autentificare Inregistrare Logare cu Facebook
top