Home
Home
Tutorials
   PHP
   Java
   Tutti...
Manuali
SmartImage
Marketing
Downloads
Contatti
Affiliati

  Da vedere
Hosting
Statistiche per siti
Corsi per webmaster
Hardware
Processori


  OnFocus
Integrare il DBMS nell'applicazione Java con SQLite

asdsad

Mambo: Unknown column 'c.access' in 'on clause'

  Siti Amici
Miki News
Giochi gratis
Areagratis
Baratto Online
AI Machines
Guide e Manuali Gratis
Web Directory
Egregio Directory
Japgalaxy
Siena Turismo
WebApocalypse
Boutique online
Add to Technorati Favorites

Tutti i siti amici
Diventa Affiliato

 


Autore: Claudio Venturini
Categoria: php
Livello: base Livello base

PHP 5 ad oggetti: overriding e keyword final

Il concetto di override, la parola chiave final, e come si ereditano costruttore e distruttore

Con questo articolo approfondiamo l'ereditarietà in PHP. Come sappiamo una classe derivata, ovvero una sottoclasse, eredita tutti i metodi della classe genitore, la classe base. Ora spiegherò più in dettaglio cosa e come viene ereditato.

Ereditare il costruttore e il distruttore

Chi viene da C++ potrebbe rimanere sorpreso da un titolo del genere. Ebbene si, il costruttore e il distruttore sono ereditabili. Ciò permette quindi di evitare di definire il costruttore e il distruttore nelle sottoclassi, poichè viene automaticamente usato quello della classe base. Per mostrare ciò riprendo l'esempio dell'articolo PHP 5 ad oggetti: usare l'ereditarietà.

<?php

// Definizione della classe Animale
class Animale {
  private $specie;

  // Costruttore
  public function __construct($specie){
    $this->specie $specie;
    echo "animale";
  }

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

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

// Definizione della classe Mammifero
class Mammifero extends Animale {
  private $corna;

  public function haCorna(){
    return $this->corna;
  }

  public function setCorna($corna){
    $this->corna $corna;
  }
}

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

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

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

// Costruisco un Mammifero e un Uccello
$mamm = new Mammifero("Leone"); // Stampa "animale"
$ucc = new Uccello("Gufo"); // Stampa "animale"

?> 

Eliminando i costruttori delle sottoclassi abbiamo risparmiato codice, e quindi ridotto il rischio di bug. Dato che stampa "animale" sia nella creazione di un Mammifero che di un Uccello, se ne deduce che viene richiamato il costruttore della superclasse.

Ovviamente in questo caso specifico sarebbe stato meglio tenere i costruttori per inizializzare gli attributi $corna (in Mammifero) e $rapace (in Uccello). Per garantire che anche l'attributo $specie sia impostato correttamente è possibile richiamare il costruttore della classe genitore tramite la parola chiave parent, che identifica appunto la superclasse Animale. Ecco l'esempio rivisto (riporto solo la parte rivista della classe Mammifero per brevità):

<?php

// Definizione della classe Mammifero
class Mammifero extends Animale {
  private $corna;

  public function __construct($specie){
    parent::__construct($specie); // chiamo il costruttore di Animale
    $corna false// inizializzo $corna
  }
}

?> 

Overriding di metodi, del costruttore, e del distruttore

Se si vuole ridefinire un metodo della superclasse in una sottoclasse, è possibile farlo. Ciò permette di avere versioni più specializzate dei metodi. Questo è quelllo che si dice overriding dei metodi.

<?php

// Definizione della classe Mammifero
class Mammifero extends Animale {
  private $corna;

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

  public function setSpecie($specie){
    if ($specie != "leone" && $specie != "leonessa"){
      die();
    }
    parent::setSpecie($specie);
  }

  public function haCorna(){
    return $this->corna;
  }

  public function setCorna($corna){
    $this->corna $corna;
  }
}

// Creo un "leone" e una "leonessa"
$mamm = new Mammifero("leone"); // Ok
$mamm = new Mammifero("leonessa"); // Ok
// Creo una "tigre"
$mamm = new Mammifero("tigre"); // die()

// Creo una tigre come se fosse un animale qualunque
$mamm = new Animale("tigre"); // Ok, nel setSpecie() di Animale non ci sono controlli

?> 

Nell'esempio abbiamo creato una versione specializzata di setSpecie(), che permette di impostare solamente "leone" o "leonessa". Per impostare il valore abbiamo sfruttanto il metodo setSpecie() della superclasse Animale, tramite parent.

E' importante notare che se si ridefinisce un metodo, anche con parametri diversi, tutti i metodi ereditati con lo stesso nome vengono nascosti! Ciò vale anche per il costruttore. Ad esempio (riporto solo la versione modificata di setSpecie() e del costruttore):

<?php

// Definizione della classe Mammifero
class Mammifero extends Animale {
  // ... resto della classe

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

  public function setSpecie(){
    parent::setSpecie("leone");
  }

  // ... resto della classe
}

// Creo un "leone" e una "leonessa"
$mamm = new Mammifero("leone"); // Errore, non c'č un costruttore con un solo parametro
$mamm->setSpecie("leonessa"); // Errore, setSpecie() non prende parametri

?> 

Ho modificato setSpecie() in modo che non prenda parametri, e il costruttore in modo che prenda due parametri. Creano oggetti Mammifero come si faceva prima si hanno errori, poichè le versioni ereditate di setSpecie() e del costruttore non sono più visibili.

La keyword final per bloccare l'ereditarietà

E' possibile impedire che una classe abbia sottoclassi, o che sia possibile l'override di un metodo. Basta specificare la keyword final prima nella dichiarazione della classe o del metodo, in questo modo:

<?php

// Una classe non ereditabile
final class MyFinalClass {

  // metodo con override non permesso
  public final function metodo(){
    // ... codice del metodo ...
  }
}

// Una classe ereditabile
class MyClass {

  // metodo con override non permesso
  public final function metodo(){
    // ... codice del metodo ...
  }
}

// Tento di estendere MyFinalClass
class MyFinalClass2 extends MyFinalClass // Fatal error, MyFinalClass non č ereditabile
  // ... codice della classe ...
}

// Estendo MyClass
class MyClass2 extends MyClass // Ok, MyClass č ereditabile

  // Tento l'override di metodo()
  public function metodo(){ // Errore, metodo() non permette l'override
    // ... codice del metodo ...
  }

}

?> 

In questo modo si può bloccare l'ereditarietà e la specializzazione di metodi particolari.

PHP 5 ad oggetti: usare l'ereditarietà Precedente Indice Successivo Le variabili in PHP, errori comuni
PHP 5 ad oggetti: usare l'ereditarietà Le variabili in PHP, errori comuni