final
avant la définition de celle-ci.
Si la classe elle-même est définie avec le mot clef final
alors celle-ci ne pourra tout simplement pas être étendue.
Cela peut être utile si vous souhaitez empêcher explicitement certains développeurs de surcharger certaines méthodes ou d’étendre certaines classes dans le cas d’un projet Open Source par exemple.
Définir une méthode finale
Illustrons cela avec quelques exemples, en commençant avec la définition d’une méthode finale.
Pour cela, on peut reprendre nos classes Utilisateur
, Abonne
et Admin
et par exemple déjà surcharger la méthode getNom()
définie dans la classe parent Utilisateur
depuis notre classe étendue Admin
:
<?php abstract class Utilisateur{ protected $user_name; protected $user_region; protected $prix_abo; protected $user_pass; protected $x = 0; public const ABONNEMENT = 15; public function __destruct(){ //Du code à exécuter } abstract public function setPrixAbo(); public function getNom(){ echo $this->user_name; } public function getPrixAbo(){ echo $this->prix_abo; } public function plusUn(){ $this->x++; echo '$x vaut ' .$this->x. '<br>'; return $this; } public function moinsUn(){ $this->x--; echo '$x vaut ' .$this->x. '<br>'; return $this; } } ?>
<?php class Admin extends Utilisateur{ protected static $ban; public function __construct($n, $p, $r){ $this->user_name = strtoupper($n); $this->user_pass = $p; $this->user_region = $r; } public function getNom(){ echo $this->user_name. '(Admin)'; } public function setBan(...$b){ foreach($b as $banned){ self::$ban[] .= $banned; } } public function getBan(){ echo 'Utilisateurs bannis : '; foreach(self::$ban as $valeur){ echo $valeur .', '; } } public function setPrixAbo(){ if($this->user_region === 'Sud'){ return $this->prix_abo = parent::ABONNEMENT / 6; }else{ return $this->prix_abo = parent::ABONNEMENT / 3; } } } ?>
Ici, lorsqu’on tente d’appeler notre méthode getNom()
depuis un objet de la classe Admin
, la définition de la méthode mère est bien surchargée et c’est la définition de la classe fille qui est utilisée.
<!DOCTYPE html> <html> <head> <title>Cours PHP & MySQL</title> <meta charset="utf-8"> <link rel="stylesheet" href="cours.css"> </head> <body> <h1>Titre principal</h1> <?php spl_autoload_register(function($classe){ require 'classes/' .$classe. '.class.php'; }); $pierre = new Admin('Pierre', 'abcdef', 'Sud'); $mathilde = new Admin('Math', 123456, 'Nord'); $florian = new Abonne('Flo', 'flotri', 'Est'); $pierre->getNom(); echo '<br>'; $mathilde->getNom(); echo '<br>'; $florian->getNom(); ?> <p>Un paragraphe</p> </body> </html>
Essayons maintenant de définir notre méthode getNom()
comme finale dans la classe Utilisateur
.
<?php abstract class Utilisateur{ protected $user_name; protected $user_region; protected $prix_abo; protected $user_pass; protected $x = 0; public const ABONNEMENT = 15; public function __destruct(){ //Du code à exécuter } abstract public function setPrixAbo(); final public function getNom(){ echo $this->user_name; } public function getPrixAbo(){ echo $this->prix_abo; } public function plusUn(){ $this->x++; echo '$x vaut ' .$this->x. '<br>'; return $this; } public function moinsUn(){ $this->x--; echo '$x vaut ' .$this->x. '<br>'; return $this; } } ?>
Comme notre méthode est définie avec le mot clef final
, on n’a plus le droit de la surcharger dans une classe étendue. Si on tente de faire cela, une erreur fatale sera levée par le PHP :
Définir une classe finale
Si on définit une classe avec le mot clef final
, on indique que la classe ne peut pas être étendue. Là encore, si on tente tout de même d’étendre la classe, le PHP renverra une erreur fatale.
<?php final class Utilisateur{ protected $user_name; protected $user_region; protected $prix_abo; protected $user_pass; protected $x = 0; public const ABONNEMENT = 15; public function __destruct(){ //Du code à exécuter } public function setPrixAbo(){} final public function getNom(){ echo $this->user_name; } public function getPrixAbo(){ echo $this->prix_abo; } public function plusUn(){ $this->x++; echo '$x vaut ' .$this->x. '<br>'; return $this; } public function moinsUn(){ $this->x--; echo '$x vaut ' .$this->x. '<br>'; return $this; } } ?>
Notez ici que déclarer une classe comme abstraite et finale n’a aucun sens puisqu’une classe abstraite est par définition une classe qui va laisser à ses classes étendues le soin d’implémenter certains de ses éléments alors qu’une classe finale ne peut justement pas être étendue.
Par définition, une classe finale est une classe dont l’implémentation est complète puisqu’en la déclarant comme finale on indique qu’on ne souhaite pas qu’elle puisse être étendue. Ainsi, aucune méthode abstraite n’est autorisée dans une classe finale.