Ieri qualcuno mi ha chiesto se programmando in PHP avessi mai usato la keyword ‘implements’. Ho risposto “raramente, uso più spesso ‘abstract’ “. Per quanto possano essere simili interfacce e classi astratte sono però due cose ben distinte. Facciamo un po’ di chiarezza.
Una classe astratta è una classe che non può essere istanziata, ma che può essere estesa da altre classi. Prendiamo per esempio questa classe astratta:
abstract class Personaggio { private $nome; public function __construct($nome){ $this->nome = $nome;} public function saluta(){ return "Ciao! Io sono ".$this->nome;} }
Se tentassimo di istanziare questa classe con
$pippo = new Personaggio("Pippo");
l’interprete PHP ci risponderebbe con: “Fatal error: Cannot instantiate abstract class Personaggio”.
Possiamo però creare una nuova classe che estenda Personaggio:
class Pippo extends Personaggio { public function __construct(){ parent::__construct("Pippo"); } }
La classe Pippo eredita i metodi e gli attributi di Personaggio e ha una redifinizione del costruttore, dove si va esplicitamente a richiamare il costruttore della classe astratta, specificando però un parametro costante per questa classe (la stringa “Pippo”). Possiamo quindi istanziare Pippo ed utilizzare i metodi della classe personaggio:
$pippo = new Pippo(); echo $pippo->saluta();
L’output di questo banale programma è la stringa “Ciao! Io sono Pippo”. Le classi astratte quindi servono quando si devono implementare della classi ha hanno alcune operazioni in comune. Le classi che estendono una classe astratta possono poi avere dei metodi propri o ridefinire i metodi già definiti nella classe astratta.
Le interfacce invece definiscono un “prototipo” di una classe. Tutte le classi che implementano un’interfaccia devono definirne tutti i metodi. Vediamo un esempio di utilizzo:
interface Personaggio { public function saluta(); } class Pippo implements Personaggio { private $nome; public function __construct(){ $this->nome = "Pippo";} public function saluta(){ return "Ciao! Io sono ".$this->nome;} } $pippo = new Pippo(); echo $pippo->saluta();
Apparentemente l’uso di una classe astratta o di una interfaccia sembra pressoché indifferente, soprattutto perché PHP non è un linguaggio fortemente tipizzato, ma il concetto che sta alla base di uno o dell’altro cambia: una classe Pippo che estende una classe astratta Personaggio è una classe di tipo “Pippo” che eredita i metodi e gli attributi della classe “Personaggio”. Una classe Pippo che implementa un’interfaccia “Personaggio” è sia una classe di tipo “Pippo” che di tipo “Personaggio”.
Questa differenza si noterebbe di più se si potesse dichiarare il tipo degli argomenti di una funzione (come ad esempio avviene in Java).
Ammettiamo che lo si possa fare anche in PHP e che abbiamo la seguente funzione:
function incontra(Personaggio $p){ $p->saluta(); }
Se usiamo le interfacce non abbiamo nessun problema a far passare come argomento un’istanza di Pippo, mentre se Pippo è una classe che ne estende una astratta Personaggio, per poter far passare come argomento della funzione una istanza di Pippo dovremmo farne il downcast a Personaggio.
Riepilogando: l’uso delle classi astratte che vengono estese è utile quando si devono implementare più classi che hanno metodi e attributi in comune, ma dove il “caso base” (la classe astratta) non è ammissibile.
L’uso delle interfacce invece è utile quando le classi devono essere dello stesso tipo, ma ogni volta devono implementare i metodi dell’interfaccia in modo differente. Vediamo ora un esempio più concreto:
// Definiamo un'interfaccia Forma con un metodo getArea() interface Forma { public function getArea(); } // Definiamo ora le implementazioni di Forma, per semplicità sono stati omessi i costruttori. Ammettiamo che comunque abbiano dei // parametri per impostare gli attributi delle varie classi class Quadrato implements Forma { public function getArea() { return $this->lato*$this->lato;} } class Cerchio implements Forma { public function getArea(){ return $this->raggio*$this->raggio*3.14;} } class Triangolo implements Forma { public function getArea(){ return $this->base*$this->altezza/2;} } // Definiamo ora una funzione in "stile Java" che stampi a video l'area di una forma function stampaArea(Forma $f){ echo $f->getArea(); } // Proviamo ad utilizzare le implementazione dell'interfaccia Forma con questa funzione $t = new Triangolo($base,$altezza); $q = new Quadrato($lato); stampaArea($t); stampaArea($q);



0 Comments
There are no comments yet...Kick things off by filling out the form below.
Leave a Comment