Redazione
a- a+

PHP5 ad oggetti: ereditarietà e classi

Vediamo che cosa è e come funziona l'ereditarietà in PHP5. Codici ed esempi.

Il concetto di ereditarietà è di fondamentale importanza per la realizzazione di gerarchie di classi che siano conformi con il paradigma object oriented. La programmazione ad oggetti già nella forma in cui è stata utilizzata può semplificare molto il lavoro del programmatore, grazie al fatto che consente di isolare le entità che interagiscono nel codice. I vantaggi che essa può fornire sono però in gran parte legati al concetto di ereditarietà.

Il motore del PHP 5 consente l’ereditarietà singola tra le classi e questo permette alla classe figlia (detta sottoclasse) di ereditare. L’ereditarietà, infatti, è la possibilità di una classe di estendere un’altra, ereditandone automaticamente tutte le proprietà e i metodi. La classe che eredita viene chiamata classe figlia, mentre la classe che fornisce proprietà e metodi viene chiamata classe genitore o superclasse. La classe figlia può inoltre definire nuove proprietà e nuove funzioni.

<?
Class Genitore{
  public $a;
  public function pubblicaGenitore(){
        echo (“funzione pubblia della classe Genitore 
”);
   }
   protected function protettaGenitore(){
        echo(“funzione protetta della classe Genitore 
”);
  }
}
Class Figlia extends Genitore{
  public $b;
  public function chiamaPubblicaFiglia(){
       $this->pubblica Genitore();
   }
   protected function chiamaProtettaFiglia(){
       $this->protetta Genitore();
  }
  public function accedeProprietaGenitore(){
       echo(“$a vale”.$this->a);
 }
}
$f=new Figlia();
$f->a=”Ereditata”;
$f->b=”membro della classe Figlia”;
$f->pubblica Genitore();
$f->chiamaPubblicaFiglia();
$f->chiamaProtettaFiglia();
$f->accedeProprietaGenitore();
?>

La keywords extends, seguita da un nome di classe, indica che la classe che si sta dichiarando è figlia della classe specificata. Come in Java, per creare una classe che estende una classe già esistente si utilizza la keyword extends. Nel codice di esempio, la classe Figlia estende la classe Genitore. Nella superclasse si è fatto uso del modificatore di accesso protected per il metodo protetta Genitore(): tutti i membri protetti di una classe sono accessibili solamente dalle classi figlie e da nessun’altra porzione di codice.

La classe Figlia accede a tutti i membri della classe Genitore per mezzo della variabile $this, in modo del tutto analogo al caso in cui fossero definiti direttamente al suo interno, così come dal codice che utilizza la classe non è possibile distinguere quali metodi sono di Figlia e quali di Genitore.

Affinché PHP sia in grado di gestire correttamente le chiamate alle funzioni e l’accesso alle variabili di istanza, è stato posto il vincolo che nel codice le classi devono apparire in ordine “genealogico”, cioè una superclasse deve sempre precedere le classi figlie. L’ereditarietà semplifica la scrittura di codice molto complesso e anche la sua riusabilità. Non vi è un limite esplicito sulla profondità della genealogia tra le classi: una classe figlia può essere a sua volta genitore di un’altra classe e così via.

Ovviamente si deve sempre tenere presente che una discendenza lunghissima può deteriorare le prestazioni, visto che ogni volta che si richiama un metodo di una superclasse in un’istanza di una classe figlia, l’analizzatore PHP deve scorrere all’indietro tutta la lista delle superclassi fino alla sua individuazione.

In PHP non è prevista l’ereditarietà multipla come nel C++: non è possibile avere una classe che estende contemporaneamente più di una classe, una classe eredita solo da un’altra classe. Quindi ogni classe ha solo un unico genitore diretto.

Negli esempi fatti si è deliberatamente evitato l’uso di costruttori e distruttori e di duplicare nella classe figlia un metodo definito nella classe genitore. In questi casi esiste una regola che chiarisce quale metodo è effettivamente eseguito, ovvero quello più specifico per la classe. Quindi, se si richiama un costruttore per la classe figlia, esso viene ricercato all’interno di questa classe, se non lo si trova, la ricerca procede a ritroso lungo la gerarchia delle classi. Il medesimo ragionamento viene fatto per qualsiasi altro metodo. Tuttavia i metodi delle classi figlie possono svolgere i medesimi compiti dei metodi omonimi nelle superclassi, in questo caso ci si troverebbe di fronte ad una duplicazione del codice. Per evitare ciò si può utilizzare la keyword: parent, la quale consente di fare riferimento ai metodi della superclasse.

Consideriamo il seguente codice di esempio che racchiude tutto ciò che abbiamo finora discusso.

<?php 

// classe Animale 
class Animale { 
   private $specie; 

// Costruttore 
   public function __construct($specie){ 
     $this->specie = $specie; 
   } 

// Ritorna la specie 
   public function getSpecie(){ 
    return $this->specie; 
   } 

// Imposta la specie 
   public function setSpecie($specie){ 
    $this->specie = $specie; 
   } 
} 

//  classe Mammifero 
class Mammifero extends Animale { 
   private $carnivoro; 

   public function __construct($specie){ 
    $this->setSpecie($specie); 
   } 

   public function isCarnivoro(){ 
    return $this->carnivoro; 
   } 

   public function setCarnivoro($carnivoro){ 
    $this->carnivoro = $carnivoro; 
   } 
} 

// classe Uccello 
class Uccello extends Animale { 
  private $rapace; 

  public function __construct($specie){ 
    $this->setSpecie($specie); 
  } 
  public function isRapace(){ 
    return $this->rapace; 
  } 

  public function setRapace($rapace){ 
     $this->rapace = $rapace; 
  } 
} 

// Creo un animale 
$anim = new Animale("Tigre"); // Cambio da tigre a rinoceronte 
$anim->setSpecie("rinoceronte"); 
// Tento di impostare che il rinoceronte non è carnivoro 
$anim->setCarnivoro (false); // Errore!!! setCarnivoro() è di Mammifero, non di Animale 

// Creo L’elefante come Mammifero 
$mamm = new Mammifero("Elefante"); 
$mamm->setCarnivoro(false); // Ok 
// Cambio da Elefante a Leone
$mamm->setSpecie("Leone"); // Ok, setSpecie() ereditato 
// Il leone è carnivoro
$mamm->setCarnivoro(true); // Ok 

// Creo un uccello 
$ucc = new Uccello("Pappagallo"); 
// Il Pappagallo è carnivoro 
$ucc->setCarnivoro(false); // Errore! setCarnivoro() non è di Uccello 
// Il Pappagallo non è rapace 
$ucc->setRapace(false); // Ok setRapace è di Uccello
?>

Come abbiamo visto, una sottoclasse eredita tutti i metodi e attributi della classe genitore. Tuttavia all’esterno rimarranno visibili solo i metodi e gli attributi public, sia quelli ereditati sia quelli definiti nella sottoclasse. Se dichiariamo una variabile con la keyword private la visibilità e quindi il suo uso rimane confinato alla classe in cui è stata dichiarata.

All’interno della sottoclasse è invece possibile usare tutto ciò che è stato dichiarato public o private. È per questo motivo che nel costruttore delle sottoclassi Mammifero e Uccello è necessario usare setSpecie() per impostare la specie. L’attributo $specie non è visibile, in quanto private.



Ti potrebbe interessare anche

commenta la notizia

C'è 1 commento
Marcello
Ti è piaciuto l'articolo?