Le interfacce, come le classi astratte, sono delle classi speciali che non possono essere istanziate ma soltanto implementate. Praticamente esse delineano la struttura di una classe. La dichiarazione di un'interfaccia è simile a quella di una classe, ma include soltanto metodi (privi di implementazione) e costanti. Non è inoltre possibile specificare le proprietà.
Qualsiasi classe implementi un'interfaccia, avrà le costanti definite automaticamente e dovrà definire a suo volta i metodi dell'interfaccia, i quali, sono tutti sono astratti e vanno tutti implementati.
Implementare un'interfaccia
Per implementare un'interfaccia in una classe si utilizza la keyword implements
:
<?php
// definizione dell'interfaccia Forma
interface Person {
// costanti
const COSTANTE = "valore";
// definizione dei metodi
public function getName();
public function setName($name, $lastname);
}
?>
Nelle interfacce possiamo definire solo metodi (di default astratti) e costanti. Infatti, come è possibile notare analizzando l'esempio precedente, in questo caso non abbiamo dichiarato i metodi come astratti tramite la keyword abstract
.
Creiamo ora la classe Student
che implementa l'interfaccia Person
. La nostra classe, quindi, dovrà definire i metodi dell'interfaccia per getName()
e setName()
.
<?php
class Student implements Person {
private $name = "";
private $lastname = "";
// implementazione dei metodi
public function getName(){
// corpo del Metodo
echo "$this->name $this->lastname";
}
public function setName($name, $lastname){
// corpo del Metodo
$this->name = $name;
$this->lastname = $lastname;
}
}
$student = new Student();
$student->setName( "Giulia", "Q" );
$student->getName();
?>
Come descritto in precedenza, non è possibile creare una classe che implementi un'interfaccia e non tutti i metodi di quest'ultima; in alternativa essa dovrà essere obbligatoriamente dichiarata come abstract
. Di conseguenza, se l'interfaccia è implementata da una classe astratta, quest'ultima può anche non ridefinire tutti i metodi, sarà compito delle ulteriori sottoclassi farlo.
Il seguente esempio:
<?php
class Student implements Person {
private $name = "";
private $lastname = "";
public function setName($name, $lastname){
// corpo del Metodo
$this->name = $name;
$this->lastname = $lastname;
}
}
$student = new Student();
$student->setName( "Giulia", "Q" );
$student->getName();
?>
genererà un errore a runtime in quanto la classe Student
non implementa il metodo getName
:
Fatal error: Class Student contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Person::getName) [...]
In PHP, possiamo implementare diverse interfacce in un'unica classe, includendo, separandoli con una virgola, una serie di nomi posizionati dopo la keyword implements
.
<?php
class MyClass implements MyInterface1, MyInterface2, MyInterface3 {
// implementazione ...
}
?>
Ciò è valido soltanto se tra di esse non sussiste alcun conflitto, ossia se tali interfacce non contengono la dichiarazione degli stessi metodi o costanti.
Ereditarietà delle interfacce
Per le interfacce è possibile usare l'ereditarietà multipla. Per estendere un'interfaccia in un'altra, come per le classi, si utilizza infatti la keyword extends
.
Nell'esempio riportato di seguito, la nuova interfaccia A
, conterrà tutti i metodi dell'interfaccia B
e C
, a cui si aggiungeranno quelle nuove, definite da A
.
<?php
interface A extends B, C, ... {
...
}
?>
In questo caso, vale la stessa condizione di quando le classi implementano le interfacce. Un'interfaccia può estendere altre interfacce se queste non hanno nessun conflitto: ciò significa che se B
definisce metodi già definiti in A
si otterrà un errore.
<?php
class Employee {
private $code;
function setCode($code) {
if ($code == "") {
echo "Name cannot be blank!";
} else {
$this->code = $code;
}
}
function getCode() {
echo "<br />"."Code: ".$this->code."<br />";
}
}
interface Person {
// costanti
const COSTANTE = "valore";
// definizione dei metodi
public function getName();
public function setName($name, $lastname);
}
class Student extends Employee implements Person {
private $name = "";
private $lastname = "";
// implementazione dei metodi
public function getName(){
// corpo del Metodo
echo "$this->name $this->lastname";
}
public function setName($name, $lastname){
// corpo del Metodo
$this->name = $name;
$this->lastname = $lastname;
}
}
$student = new Student();
$student->setName( "Giulia", "Q" );
$student->getName();
$student->setCode("04022012");
$student->getCode();
?>
Differenze tra classi astratte ed interfacce
Classi astratte ed interfacce sono simili tra loro, ma differiscono per alcune caratteristiche.
Classi astratte
- Una classe astratta può contenere variabili e metodi implementati;
- nella classe astratta un metodo può essere dichiarato
asbract
; - i metodi di una classe astratta possono essere definiti con qualsiasi visibilità (
public
,protected
oprivate
).
Interfacce
- Un'interfaccia può contenere solo definizioni di metodi e costanti;
- nelle interfacce tutti i metodi sono
abstract
di default; - la visibilità dei metodi può essere solo
public
.
Le classi astratte e le interfacce, se usate adeguatamente, possono portare enormi benefici alle nostre gerarchie OOP. Nella prossima lezione parleremo dei Traits
e di come questi permettono di superare alcune limitazioni sulla gestione dell'ereditarietà singola in PHP.