devdev / in the loop
PHP PHP

Guida PHP 7 guru
Le interfacce (interface)

Le interfacce (o interface) non sono un costrutto nuovissimo, ma sicuramente rappresentano uno dei punti cardine quando andiamo ad implementare nel nostro progetto dei componenti esterni.

In due parole, una interface dichiara quali metodi e proprietà un oggetto DEVE avere. Sembra allo stesso tempo semplice e spettacolare. Vi posso confermare che è così.

Una interface semplifica, come dicevamo, l’interazione tra due oggetti PHP dichiarando quali metodi e/o proprietà un oggetto deve possedere se vuole usare una tale interfaccia. È fondamentale capire che definire una interface non significa scrivere il codice dei suoi metodi, ma si basa sul fatto che essi esistono in chi la implementa.

Un secondo oggetto che vorrà implementare tale interfaccia, quindi, dovrà definire il funzionamento dei metodi.

Una interface, quindi, definisce una sorta di standard che chiunque voglia implementarla deve rispettare, pena la generazione di un fatal error. Questa logica è funzionale allo scrivere oggetti che si aspettano un comportamento specifico da altri oggetti. Si potrebbe pensare al fatto che ogni oggetto Automobile possiede dei metodi generici, come mettiInMoto() che l’oggetto Pilota chiamerà: quando saliamo in auto infatti ci aspettiamo uno sterzo, un cruscotto e la possibilità appunto di mettere in moto il veicolo.

<?php

class Pilota {

    function prontoAPartire(mezzoAMotore $mezzo) {
        $mezzo->mettiInMoto();
    }
}

Il fatto è che ogni automobile poi avrà tecnicamente un modo diverso di messa in moto sotto il cofano (pensiamo ad un diesel diverso da un benzina), ma alla classe Pilota (cioè a noi) questo non interessa: noi chiameremo il metodo mettiInMoto()  su qualsiasi auto saliamo, non ci importa di come l’ha implementata il costruttore dell’auto. Questo, pensiamoci, potrebbe valere non solo per le automobili ma anche per una motocicletta o un motoscafo. Possiamo dire, quindi, che chi fabbrica veicoli deve rispettare l’interface mezzoAMotore se vuole che una persona possa guidare i loro mezzi e che quando noi utilizziamo un oggetto che rispetta questa interface ci troveremmo sempre e comunque un metodo mettiInMoto(). Possiamo notare che il metodo prontoAPartire() della classe Pilota sembra accettare un istanza di tipo mezzoAMotore che però non è una classe ma appunto una interface. Questo metodo chiamerà immediatamente il metodo mettiInMoto() di questa istanza che gli viene passata.

<?php

interface mezzoAMotore {

    public function mettiInMoto();
    public function accelera();
}

Definire una interface, come vediamo, è piuttosto semplice: utilizziamo la keyword interface e le assegniamo un nome. Assomiglia molto a quando scriviamo una semplice classe. A differenza di questa però, qui i metodi vanno soltanto dichiarati e non dobbiamo scriverne il contenuto. Qui è ancora più lampante che in fondo stiamo creando “una specie di standard” per i mezzi a motore: chi infatti vorrà implementare questa interfaccia dovrà scrivere (liberamente!) il codice dei metodi mettiInMoto() e accelera(). Perché lo facciamo? Perché la classe Pilota si aspetta che l’oggetto con il quale interagirà (auto, moto, barca) abbia questi due metodi.

Ora proviamo a scrivere le classe Automobile e Moto che implementeranno entrambe l’interface mezzoAMotore :

<?php

class Automobile implements mezzoAMotore {

    public function mettiInMoto() {
        // ... codice
    }

    public function accelera() {
       // ... codice
    }

    public function accendiClimatizzatore(int $gradi) {
        
        // Questo metodo esiste solo in questa classe

    }

}



class Moto implements mezzoAMotore {

    public function mettiInMoto() {
        // ... codice
    }

    public function accelera() {
       // ... codice
    }

    public function impenna() {
        
        // non ve la descrivo

    }

}

Per implementare un’interfaccia, come abbiamo appena visto, dobbiamo utilizzare la keyword implements seguita dal nome dell’interface. Qui scriviamo il codice dei metodi che Automobile e Moto devono avere perché implementano l’interface mezzoAMotore. Saremo naturalmente liberi di aggiungere altri metodi e proprietà indipendenti dall’interfaccia, proprio come facciamo quando usiamo l’ereditarietà degli oggetti in PHP. In questo caso, abbiamo aggiunto una specializzazione di un automobile che non troveremo certo su una moto o barca, ovvero il metodo accendiClimatizzatore() e per la classe Moto il metodo impenna() che non sto qui a spiegarvi.

<?php

// Questo è il codice principale del progetto

$pilota = new Pilota;
$macchina = new Automobile;
$barca = new Barca;

$pilota->prontoAPartire($macchina);
$pilota->prontoAPartire($barca);

Vediamo quindi come la classe Pilota, chiamerà in ogni caso il suo metodo prontoAPartire()  accettando come parametro un oggetto che implementa l’interfaccia mezzoAMotore , che, proprio per questo motivo dovrà avere a sua volta il metodo mettiInMoto() .

Il grande vantaggio di astrazione che le interface ci offrono è poter scrivere del codice sapendo che altre classi hanno necessariamente dei metodi (dei quali potremmo anche ignorare il funzionamento) che queste interface definiscono. Potremmo quindi invitare chiunque a scrivere una classe che implementa l’interface mezzoAMotore senza cambiare il nostro codice principale del progetto e quindi l’interazione con l’oggetto Pilota.

Le interfacce possono essere estese

Analogamente agli oggetti, anche le interfacce possono sfruttare il principio dell’ereditarietà:

<?php

interface mezzoAMotore extends mezzoGenerico {

}

 

Capitolo successivo → Guide complete
Precedente ← I namespace
if (weekend) {
    relax();
}
la nostra newsletter, ogni tanto.