Con lezione precedente abbiamo imparato un altro dei concetti fondamentali della programmazione orientata agli oggetti, ovvero quello di overriding o ridefinizione di un elemento. Abbiamo analizzato tutte le possibili situazioni in cui è possibile attuare l'overriding e l'importanza della keyword parent
.
Tuttavia, possiamo fare anche in modo di impedire l'overriding. Ad esempio, se prendiamo in considerazione una classe che contiene metodi che svolgono operazioni fondamentali (come la connessione ad un database, il parsing di documenti XML e così via), possiamo decidere di non permettere la ridefinizione di questi metodi che potrebbe causare instabilità all'interno della gerarchia e di conseguenza di tutta l'applicazione.
Per questo ci occorre una strategia per impedire l'overriding. Questo è possibile grazie alla parola chiave final
, che utilizzata in combinazione con l'indicatore di visibilità desiderato e con il nome del metodo, implica che quest'ultimo non potrà essere ridefinito dalla classe eredi. Ecco un esempio:
class MyClass {
final public function connect_to_my_db() {
// implementazione...
}
final public function parse_my_xml_doc() {
// implementazione...
}
final public function sayHello() {
echo "Hello!";
}
}
$myClass = new MyClass();
// stampa "Hello!"
$myClass->sayHello();
Come possiamo vedere, i metodi dichiarati con la keyword final
si comportano esattamente come le controparti normali. La differenza occorre quando tentiamo di ridefinire i metodi in questione:
class AnotherClass extends MyClass {
public function sayHello() {
echo "Hello!";
}
}
Il tutto risulterà in un Fatal Error che ci dirà che non è possibile ridefinire il metodo sayHello
della classe MyClass
, poichè quest'ultimo è stato dichiarato come final
:
Fatal error: Cannot override final method MyClass::sayHello() in [...]
Classi final
Una particolarità interessante offerta dalla keyword final
è che quest'ultima, oltre che con i metodi, può essere utilizzata in collaborazione con le classi. Dichiarando una classe come final
infatti (la parola chiave "final" deve precedere il nome della classe), quest'ultima non potrà essere estesa da nessuna sottoclasse:
final class MyClass {
// implementazione...
}
Anche in questo caso, tentare di estendere la classe MyClass porta ad un Fatal Error:
class AnotherClass extends MyClass {
// implementazione...
}
Fatal error: Class AnotherClass may not inherit from final class (MyClass) in [...]
La decisione di dichiarare le classi come final
potrebbe apparire come priva di significato, dato che il nucleo della OOP si basa sull'estensione delle classi, ed effettivamente è un criterio che va usato con cautela. Tuttavia, ci sono parecchi casi reali dove dichiarare le classi come final
rappresenta la soluzione migliore e più sicura per la stabilità dell'applicazione. Ad esempio, se abbiamo una gerarchia di classi per gestire le diverse tipologie di utenti, potremmo avere una classe SimpleUser
che definisce un utente normale ed una classe AdministerUser
che definisce gli amministratori con dei privilegi speciali. Sarebbe meglio fare in modo che quest'ultima classe non possa essere estesa da ulteriori sottoclassi, che implementerebbero tutti i suoi privilegi.
Conclusione
Con questa lezione dedicata alle tecniche per impedire la ridefinizione di metodi e l'estensione delle classi, si conclude il secondo ciclo della guida. Il prossimo step comprende due argomenti avanzati, la cui conoscenza è fondamentale nella programmazione orientata agli oggetti di PHP: le classi astratte e le interfacce, tramite le quali è possibile creare vere e proprie API, uniformare il comportamento delle classi ed astrarre le funzionalità da esse offerte: l'ideale per gestire i lavori e le collaborazioni in Team.