Les classes et les objets en PHP
#1 Qu'est-ce qu'une classe ? Qu'est-ce qu'un objet ?
Une classe, c'est une déclaration dans laquelle on va associer une structure de données à des fonctionnalités qui manipulent cette structure 😃.
La classe, c'est juste un modèle. On se sert de la classe pour construire des objets. On dit que l'on instancie la classe. Dans un objet, des variables, correspondant à la structure de données de la classe, sont allouées et initialisées avec des valeurs. Avec une classe, on construit autant d'objets que l'on veut.
#2 Déclarer la classe
Je fais un exemple. J'ai une boutique en ligne dans laquelle je mets en vente des articles.
Ci-dessous, je déclare une classe Article
. Je mets un A majuscule au nom de cette classe. Je mets la classe dans un fichier qui porte le même nom qu'elle. Je mets une seule classe par fichier. Tout ça, ce sont des conventions. L'interpréteur PHP ne connait rien de ces conventions. Il n'est même pas case sensitive sur le nom de cette classe.
Dans la classe Article
, je vais déclarer une liste de variables, qui va correspondre à la liste des caractéristiques de chaque article. Il y aura un nom, une référence et un prix hors taxes. Ces variables, on les appelle des propriétés. Ce sont ces variables qui constituent la structure de données dont j'ai parlé jusqu'à présent.
Ces propriétés doivent être déclarées avec un modificateur de visibilité. Si on met le mot réservé public
, les propriétés sont vues de l'extérieur. Si on met le mot réservé private
, les propriétés sont cachées, on ne les voit que dans la classe.
Maintenant, je vais déclarer les fonctionnalités dont j'ai besoin. Pour tous mes articles, j'ai besoin de calculer le prix TTC. Je vais donc déclarer une fonction calculerPrixTTC
qui va faire ce calcul. Dans une classe, cette fonction s'appelle une méthode.
#3 Construire des objets
Maintenant, je veux vendre un sac à dos et des skis de rando. J'ai besoin de vrais articles. Ce que je vais faire, c'est que je vais me servir de la classe comme modèle pour construire mes vrais articles. Mes vrais articles vont être des objets.
Pour construire mes articles, je fais un new
et je mets la liste des données qui concernent l'article que je construis.
Ci-dessous, vous voyez que la structure de données de la classe a été utilisée pour fabriquer, dans chaque objet, une liste de variables dans lesquelles sont stockées les valeurs des caractéristiques de chaque objet. Vous pouvez fabriquer autant d'objet que vous voulez. Chaque objet aura sa liste de caractéristiques.
Alors là, il me manque quelque chose. Comment affecter les variables qui sont prévues dans la classe avec les données de mes articles ?
PHP va venir à mon secours. Lorsque je fais le new Article()
, PHP appelle une fonction constructeur. Cette fonction s'appelle une fonction constructeur car elle construit l'objet. En PHP, le nom de cette fonction est __construct
. C'est une méthode qui fait partie des méthodes magiques.
PHP appelle le __construct
, mais il ne sait pas ce que moi, je veux en faire. Du coup, c'est moi qui vais coder le __construct
. J'ai besoin que PHP passe à __construct
les valeurs passées en arguments du new
. Ca tombe bien, c'est ce qu'il va faire. Du coup, je vais me servir de ces valeurs pour aller affecter les variables qui sont prévues dans la classe. Attention, il va me falloir un jeu de variables pour chaque objet, car chaque article a son prixHT, son nom, sa référence.
#4 D'où sort ce $this ?
Pour créer un objet, PHP doit allouer de la mémoire pour y ranger les variables avec les valeurs de l'objet qu'il est en train de créer. Si vous demandez la création d'un nouvel objet, PHP allouera de nouveau de la mémoire pour un nouveau jeu de variables et de valeurs.
Lorsque PHP alloue de la mémoire, il fait de l'allocation dynamique de mémoire et il récupère l'adresse de cette mémoire dans la variable $this
. Donc this
pointe sur l'objet qui est en cours de construction. On dit aussi que this
désigne l'instance.
Maintenant, je vais accéder à une propriété. Je fais un echo $article1->nom
et un echo $article2->nom
. Et ça marche ! Que s'est-il passé ?
$article1
et $arcticle2
ont récupéré les valeurs de $this
. Il y a donc eu une sorte de return
à la fin de l'exécution de __construct()
et donc sur le new
.
$article1
et $article2
sont donc des références. Comprenez ce que ça implique : si vous passez un objet à une fonction et que vous modifiez l'objet dans la fonction, alors, vous conserverez cette modification après l'appel de la fonction.
Et les méthodes ? Les méthodes sont partagées par tous les objets de la même classe. S'il y a 1000 objets article
, vous imaginez bien que PHP ne va pas implanter 1000 fois calculerPrixTTC()
en mémoire. Par conséquent, si on modifie une méthode, eh bien tous les objets voient la modification.
Maintenant, on va terminer le codage de calculerPrixTTC()
et on va l'appeler.
#5 Le destructeur
De la même manière que PHP appelle le constructeur au moment du new
, PHP appelle aussi un destructeur. Cet appel se produit à la fin du script ou sur un unset
d'un objet. Dans l'exemple ci-dessous, le destructeur est appelé à la fin du script et pour chaque objet.
#6 La promotion du constructeur en PHP8
Souvent, d'une classe à une autre, dans le constructeur, on fait la même chose, à savoir que l'on déclare la liste des propriétés et ensuite, on les initialise.
En PHP8, une amélioration est apportée. Tout paramètre de __construct
qui est déclaré avec un modificateur de visibilité devient une propriété. La propriété sera initialisée avec l'argument correspondant au moment de l'appel du __construct
. En PHP8, c'est ce que l'on appelle la promotion du constructeur.
#7 L'héritage
Maintenant, je veux mettre des articles en promotion. Je veux faire une remise dessus. Pour faire ça, j'ai besoin d'une classe Promotion
avec quatre propriétés : nom, référence, prixHT et remise. Et j'ai aussi besoin d'une nouvelle méthode calculerPrixPromotion()
.
Alors, j'aimerais bien ne pas tout recommencer et c'est possible. Pour ça je vais utiliser l'héritage. Je vais construire une classe Promotion
qui va étendre la classe Article
. Promotion
va être la classe fille et Article
la classe mère.
La classe Promotion
va hériter des propriétés de la classe Article
et de ses méthodes. De toutes ses méthodes, y compris des méthodes magiques, c'est-à-dire ici du constructeur __contruct
. Toutefois, on ne va pas pourvoir se contenter du constructeur de la classe Article
, car il ne prend pas la remise
en argument. On va donc être obligé d'écrire un nouveau constructeur __construct
dans la classe Promotion
. Ce nouveau constructeur prendra comme arguments, les quatre arguments nécessaires à la construction de Promotion
. C'est lui qui sera appelé au moment d'un new Promotion()
.
Quand on réécrit dans une classe fille une méthode qui existe déjà dans la classe mère, on dit que l'on surcharge la méthode de la classe mère. Donc, ici le __construct
de la classe fille surcharge le __construct
de la classe mère.
Le constructeur de la classe fille fait deux choses :
- Il initialise les propriétés qui sont dans la classe fille. Donc ici, il initialise juste la propriété
$this->remise
. - Il initialise les propriétés de la classe mère, en appelant le constructeur de la classe mère. Pour cela, il utilise l'opérateur de résolution de portée
::
avec le mot réservéparent
.
Pour appeler la méthode calculerPrixTTC()
de la classe mère, il utilise également parent::
.
#8 Les constantes de classe
Les constantes de classe sont des constantes qui sont déclarées dans la classe. PHP vous autorise à les déclarer sans modificateur de visibilité. Par défaut, elles sont public
. Ces constantes sont allouées dans la classe et restent dans la classe. Elles sont partagées par tous les objets qui sont instance de cette classe.
- Pour utiliser une constante de classe dans la classe, il faut utiliser
self::
. Notez bien une chose ici,self::
désigne la classe etthis->
désigne l'instance. - Pour utiliser une constante de classe à l'extérieur de la classe, il faut mettre le nom de la classe suivi de
::
.
#9 L'encapsulation
L'encapsulation consiste à cacher un certain nombre de choses dans la classe. En fait, on cache tout ce que l'on ne veut pas mettre à disposition. Ca peut être des propriétés ou des méthodes. Un jeu de classe permet de développer des couches logicielles qui sont indépendantes et étanches.
Pour encapsuler, on utilise les mots réservés private
et protected
. Si vous mettez protected
sur une propriété, alors, vous ne pouvez pas la voir depuis l'extérieur de la classe, sauf depuis une classe fille.
Le plus souvent, ce que l'on fait, c'est que l'on met une propriété private
ou protected
. Ensuite, on utilise des fonctions spéciales, que l'on appelle des assesseurs (* les getters) et des mutateurs (* les setters) pour donner un accès contrôlé à la propriété.
Je le fais ci-dessous pour la remise. Dans le setter, je vérifie que la remise est bien comprise entre 1% et 50%.