6. Interfacce
Un'interfaccia è una struttura che definisce i prototipi dei metodi. Una classe che implementa un'interfaccia deve definire il codice per tutti i metodi dell'interfaccia.
6.1. L'albero degli script

6.2. Una prima interfaccia
Definiamo un'interfaccia [IExample] in uno script [IExample.php]. Nello stesso script, definiamo due classi che implementano l'interfaccia [IExample]:
<?php
// strict adherence to function parameter types
declare(strict_types=1);
// namespace
namespace Exemples;
// an interface
interface IExemple {
// interface methods
public function ajouter(int $i, int $j): int;
public function soustraire(int $i, int $j): int;
}
// implementation 1 of the IExemple interface
class Classe1 implements IExemple {
public function ajouter(int $a, int $b): int {
return $a + $b + 10;
}
public function soustraire(int $a, int $b): int {
return $a - $b + 20;
}
}
// implementation 2 of the IExemple interface
class Classe2 implements IExemple {
public function ajouter(int $a, int $b) : int{
return $a + $b + 100;
}
public function soustraire(int $a, int $b) : int {
return $a - $b + 200;
}
}
Commenti
- righe 10–14: L'interfaccia IExample definisce due metodi: la funzione add (riga 12) e la funzione subtract (riga 13). L'interfaccia non definisce il codice per questi metodi. Saranno le classi che implementano l'interfaccia a farlo;
- riga 17: La classe Class1 implementa l'interfaccia IExample. Definisce quindi il codice per il metodo add (riga 18) e il metodo subtract (riga 22);
- righe 29–38: lo stesso vale per la classe Class2;
Utilizziamo l'interfaccia [IExemple] nel seguente script [interfaces-01.php]:
<?php
require_once "IExemple.php";
use \Exemples\Classe1;
use \Exemples\Classe2;
use \Exemples\IExemple;
// function
function calculer(int $a, int $b, IExemple $interface) : void {
print $interface->ajouter($a, $b)."\n";
print $interface->soustraire($a, $b)."\n";
}
// ------------------- hand
// creation of 2 objects of type Class1 and Class2
$c1 = new Classe1();
$c2 = new Classe2();
// call the calculate function
calculer(4, 3, $c1);
calculer(14, 13, $c2);
Commenti
- righe 3–6: inclusione e definizione delle classi e delle interfacce utilizzate dallo script;
- riga 3: invece dell'istruzione include, qui abbiamo utilizzato l'istruzione require_once. L'istruzione include inserisce un file nello script corrente anche se è già stato incluso, mentre l'istruzione require_once lo include una sola volta. Pertanto, quando si tratta di includere codice, preferiamo l'istruzione require_once;
- Righe 9–12: definiamo una funzione;
- Riga 9: qui dichiariamo i tipi dei tre parametri. Se, in fase di esecuzione, il parametro effettivo non è del tipo previsto, viene generato un errore. Il terzo parametro è di tipo [IExample]. Ciò significa che il parametro effettivo deve essere un'istanza di una classe che implementa l'interfaccia [IExample]; nel nostro esempio, ciò significa un'istanza delle classi [Class1] o [Class2];
- Righe 10–11: utilizziamo i metodi [add, subtract] dell'interfaccia [IExample];
- riga 19: il terzo parametro effettivo è di tipo [Class1], che è compatibile con il tipo [IExample] del terzo parametro formale della funzione;
- riga 20: lo stesso vale per la classe [Class2];
Risultati
6.3. Derivazione di un'interfaccia
Proprio come una classe figlia può estendere una classe padre, un'interfaccia figlia può estendere un'interfaccia padre.
Si consideri l'interfaccia [IExample2] definita nel file [IExample2.php]:
<?php
// strict adherence to function parameter types
declare(strict_types=1);
// namespace
namespace Exemples;
// interface definition IExemple included
require_once __DIR__."/IExemple.php";
// an interface derived from IExemple
interface IExemple2 extends IExemple {
// the interface method
public function multiplier(int $i, int $j): int;
}
// implementation of IExemple2 interface
class Classe3 extends Classe2 implements IExemple2 {
public function multiplier(int $a, int $b): int {
return $a * $b;
}
}
Commenti
- riga 6: l'interfaccia [IExample2] si troverà nello stesso spazio dei nomi dell'interfaccia [Iexample];
- riga 9: viene incluso il file di definizione dell'interfaccia [Iexample];
- righe 12–15: definiscono l'interfaccia [IExample2], che estende (eredita da) l'interfaccia [IExample] e aggiunge un nuovo metodo ad essa (riga 14);
- righe 18–24: la classe [Class3] estende la classe [Class2]. Poiché [Class2] implementa l'interfaccia [IExample], anche [Class3] la implementerà. Infatti, [Class3] eredita tutti i metodi pubblici e protetti della classe [Class2], compresi i metodi add e subtract. Inoltre, specifichiamo che [Class3] implementa l'interfaccia [IExample2]. In quanto tale, deve implementare anche il metodo multiply, che [Class2] non implementa. Questo è ciò che fanno le righe 20–22;
L'interfaccia [IExample2] viene utilizzata dal seguente script [interfaces-02]:
<?php
// strict adherence to function parameter types
declare(strict_types=1);
// inclusion and qualification of classes and interfaces required by the script
require_once __DIR__."/Iexemple2.php";
use \Exemples\IExemple2;
use \Exemples\Classe3;
// function
function calculer(int $a, int $b, IExemple2 $interface) {
print $interface->ajouter($a, $b) . "\n";
print $interface->soustraire($a, $b) . "\n";
print $interface->multiplier($a, $b) . "\n";
}
// ------------------- hand
// creation of 1 Class3 object implementing IExemple2
$c3 = new Classe3();
// call the calculate function
calculer(4, 3, $c3);
Commenti
- riga 12: il terzo parametro della funzione [calculate] è di tipo [IExample2];
- righe 13–15: vengono utilizzati i tre metodi dell'interfaccia [IExample2];
- riga 22: la funzione [calculate] viene chiamata con un oggetto di tipo [IExample2] come terzo parametro (riga 20);
Risultati
6.4. Passaggio di un'interfaccia come parametro di una funzione
Abbiamo visto nella sezione precedente che quando il tipo previsto per un parametro di funzione è una classe, il parametro effettivo può essere un oggetto del tipo previsto o di un tipo derivato. Lo stesso vale per le interfacce, come mostrato nel seguente script [interfaces-03.php]:
<?php
// strict adherence to function parameter types
declare(strict_types=1);
// inclusion and qualification of classes and interfaces required by the script
require_once __DIR__."/IExemple.php";
use \Exemples\IExemple;
require_once __DIR__."/IExemple2.php";
use \Exemples\Classe3;
// function
function calculer(int $a, int $b, IExemple $interface) {
print $interface->ajouter($a, $b) . "\n";
print $interface->soustraire($a, $b) . "\n";
}
// ------------------- hand
// creation of 1 object of type Class3 which implements IExemple2 and therefore IExemple
$c3 = new Classe3();
// call the calculate function
calculer(4, 3, $c3);
Commenti
- riga 13: la funzione [calculate] si aspetta un tipo [IExample] come terzo parametro. Ciò significa che il tipo effettivo del parametro può essere [IExample] o un tipo derivato;
- riga 20: istanziamo un oggetto $c3 di tipo [Class3], una classe che implementa l'interfaccia [IExample2], la quale a sua volta estende l'interfaccia [IExample]. Quindi, in definitiva, $c3 implementa l'interfaccia [IExample];
- riga 22: chiamiamo la funzione [calculate] con un oggetto $c3 di tipo [Class3] come terzo parametro. Grazie all'interazione tra ereditarietà di classe e implementazioni, abbiamo visto che l'oggetto $c3 implementa il tipo [IExample]. Possiamo quindi utilizzarlo come terzo parametro;
Risultati