Blog ENI : Toute la veille numérique !
🎁 Jusqu'au 25/12 : 1 commande de contenus en ligne
= 1 chance de gagner un cadeau*. Cliquez ici
🎁 Jusqu'au 31/12, recevez notre
offre d'abonnement à la Bibliothèque Numérique. Cliquez ici
  1. Livres et vidéos
  2. Apprendre à développer des applications web avec PHP et Symfony (2e édition)
  3. Le langage Objet
Extrait - Apprendre à développer des applications web avec PHP et Symfony (2e édition)
Extraits du livre
Apprendre à développer des applications web avec PHP et Symfony (2e édition)
2 avis
Revenir à la page d'achat du livre

Le langage Objet

Introduction

Voici la notion la plus intéressante de la programmation PHP.

Pas de panique, même si le mot objet semble étrange, il ne traduit somme toute que des éléments de programmation simples et logiques destiné à vous simplifier la vie.

Sans plus attendre, plongeons avec bonheur dans le monde merveilleux du langage Objet !

Des objets en programmation

Avant d’expliquer pourquoi on parle d’objets, nous allons vous dévoiler simplement ce que cela signifie en programmation.

Nous avons vu précédemment la notion de variable, qui permet de stocker des informations pour les réutiliser ultérieurement.

Nous avons également vu la notion de fonction qui permet d’utiliser le même code plusieurs fois, avec des paramètres différents.

La suite logique est donc d’avoir un élément qui contient à la fois des variables et des fonctions. C’est ce qu’on appelle un objet.

Un objet est avant tout une variable qui, au lieu de contenir une valeur, va contenir des variables et des fonctions. On dit que la variable est de type objet

Les objets existent dans la plupart des langages de programmation. Leur création diffère d’un langage à l’autre mais, il existe un standard de création que PHP utilise : la classe.

À quoi cela peut-il servir ? Comme un objet peut contenir beaucoup de choses et que plusieurs objets risquent d’avoir besoin des mêmes fonctions ou des mêmes variables, pour éviter les redondances, on va créer une sorte de modèle qui permettra de créer les objets.

Les classes

Une classe est donc un modèle qui va permettre de créer un ou plusieurs objets. 

Comment crée-t-on une classe ?

On utilise le mot-clé class :

<?php 
 
// déclaration d'une classe 
class NomDeMaClasse 
{ 
 
    public $maPremiereVariable=valeur ; 
    public $maDeuxiemeVariable=valeur ; 
    ... 
    maPremiereFonction(parametres...) 
    { 
 
         ... 
    } 
 
    maDeuxiemeFonction(parametres...) 
    { 
 
         ... 
    } 
} 

Les { } de la classe encapsulent toutes les variables et toutes les fonctions de la classe.

Notez le nom de la classe : NomDeMaClasse. Le premier mot commence par une majuscule à l’inverse des variables et des fonctions. On utilise de manière standard la PascalCase au lieu de la camelCase. Ce n’est pas obligatoire, mais recommandé.

Notez également le mot-clé public devant les variables, c’est la portée de la variable, nous en reparlerons plus tard. Il est obligatoire, si vous l’omettez, vous aurez...

Les objets

Pour créer un objet à partir d’une classe, on utilise le mot-clé new puis le nom de la classe. On dit qu’on instancie la classe. Il est possible d’avoir autant d’instances de la classe qu’on le souhaite.

Syntaxe :

 
$monObjet=new NomDeMaClasse;  

Une fois l’objet instancié, on peut accéder à ses variables ou à ses fonctions à l’aide de l’instruction -> (touche tiret du 6, puis la touche > sous Windows) :

$monObjet->maVariable; // pour accéder à la variable maVariable 
$monObjet->maFonction(); // pour accéder à la fonction maFonction 

Notez qu’il n’y a pas le $ devant le nom de la variable (maVariable par exemple).

Nous allons créer l’objet imprimante à partir de la classe Produit. Voici le code :

<?php 
// Ici la déclaration de la classe 
... 
// Affectation des valeurs des variables 
$imprimante=new Produit; 
$imprimante->nom="imprimante"; 
$imprimante->prix=700; 
$imprimante->quantite=20; 
$imprimante->rupture=false; 
 
// Affichage des valeurs des variables  
// Nous utilisons la concaténation 
echo "Nom du produit : ".$imprimante->nom."<br>"; 
echo "Prix du produit : ".$imprimante->prix."<br>"; 
echo...

Les propriétés et les méthodes d’un objet

Pour distinguer les variables et les fonctions d’une classe, des variables et des fonctions habituelles nous utilisons un autre vocabulaire :

  • Les variables d’une classe sont appelées les propriétés de la classe (on dit parfois attributs).

  • Les fonctions d’une classe sont appelées les méthodes de la classe.

C’est ce vocabulaire que nous utiliserons dans la suite de l’ouvrage.

Pourquoi le langage est-il dit objet ?

Pourquoi appelle-t-on ce nouveau type de variable, des objets ?

L’être humain aime bien faire des analogies entre ce qu’il fait et la vie réelle. Il est vrai qu’il y a une analogie entre la définition de nos objets tels qu’on vient de les décrire dans le code et celle des objets de la vie réelle.

Reprenons notre exemple :

La classe Produit décrit un produit réel disponible dans un magasin.

Ce produit a certaines caractéristiques qui le définissent : son nom, son prix, la quantité disponible… Ce sont les propriétés de l’objet.

On pourrait également prendre l’exemple d’une voiture dont les propriétés seraient : la marque, la couleur, le nombre de portes…

Les objets disposent aussi de certaines facultés : on peut démarrer en langage objet la voiture, la faire accélérer, la faire ralentir et l’arrêter. C’est ce qu’on appelle les méthodes de l’objet.

Dans notre exemple, Produit a trois méthodes. Il est possible d’ajouter un produit, supprimer un produit et afficher les propriétés d’un produit.

Les propriétés d’un objet s’apparentent aux caractéristiques physiques d’un objet dans la réalité.

Les méthodes...

L’objet $this

Il est souvent bien utile dans une méthode d’une classe de pouvoir utiliser les propriétés de cette classe.

De même, il pourrait être utile d’appeler une méthode d’une classe à partir d’une autre méthode de la même classe.

Malheureusement, il n’est pas possible d’appeler ces éléments directement par leur nom. Ce ne sont pas des variables ni des fonctions élémentaires.

Il est nécessaire de passer par l’objet instancié pour atteindre ses propriétés ou ses méthodes, en utilisant l’outil - >.

Mais à la déclaration de la classe, nous ne connaissons pas le nom de l’objet qui va être instancié.

Il faut donc qu’à l’intérieur de la classe, nous puissions systématiquement définir l’objet sur lequel nous sommes pour pouvoir utiliser ses propriétés et ses méthodes.

C’est pourquoi a été créé l’objet $this.

$this représente par défaut l’objet qui instancie la classe. Ainsi, nous pouvons, à la déclaration de la classe, appeler les propriétés et les méthodes de l’objet qui instanciera la classe.

Syntaxe :

<?php 
class NomDeMaClasse 
{ 
 
    public $maPremiereVariable=valeur ; 
    public $maDeuxiemeVariable=valeur ; 
    ... 
    maPremiereFonction(parametres...) 
    { 
 
         // accès aux propriétés de la classe 
         $this->maPremiereVariable ... 
 
         // accès aux méthodes de la classe 
         $this->maDeuxiemeFonction(parametres) 
    } 
 
    maDeuxiemeFonction(parametres...) 
    { 
 
         ... 
    } 
 
}  

$this ne s’utilise qu’à...

Les méthodes magiques

En effet, il y a de la magie dans la programmation objet !

Les méthodes sont dites magiques quand elles s’exécutent sans qu’on les appelle directement.

Oui, mais alors quand ?

Tout dépend de la méthode magique.

Une méthode magique a un rôle prédéfini. Elle s’exécute lorsqu’un certain évènement arrive. Un évènement, c’est, par exemple, l’instanciation d’une classe, l’affichage d’un objet, l’accès en lecture ou écriture d’une propriété…

Il existe de nombreuses méthodes magiques. Vous les trouverez toutes ici : https://www.php.net/manual/fr/language.oop5.magic.php

Nous allons explorer les méthodes magiques les plus utilisées.

1. La méthode __toString()

Cette méthode se déclenche dès que l’objet est traité comme une chaîne de caractères. C’est à vous de définir cette méthode dans la classe.

Le __ devant chaque méthode magique s’obtient avec deux caractères _ (underscore).

Exemple : nous avons l’objet $imprimante et nous voulons faire afficher notre objet en faisant : echo $imprimante;

Un echo ne peut pas afficher un objet, sauf si cet objet contient la méthode magique __toString().

Pour pouvoir faire echo $imprimante, il suffit de remplacer la méthode précédente afficherProduit() par __toString() :

<?php 
 
class Produit 
{ 
 
    public $nom="mon Produit"; 
    public $quantite=3; 
    public $prix=120; 
    public $rupture=false; 
 
    function __toString() 
    { 
        return "Nom: ".$this->nom.'<br>'. 
               "Prix: ".$this->prix.'<br>'. 
               "Quantité: ".$this->quantite.'<br>'. 
               (($this->rupture)?"Rupture de stock<br>":"En  
    stock<br>"); 
    } 
    function ajouterProduit() 
    { 
        $this->quantite+=1; 
        if($this->quantite>0) $this->rupture=false; 
    } 
    function supprimerProduit() 
    { 
        $this->quantite-=1; 
        if($this->quantite<=0){ 
            $this->quantite=0; 
            $this->rupture=true; 
        } ...

Les espaces de noms

Pour l’instant, la classe utilisée est définie à l’intérieur du script qui l’utilise.

Mais il est plus judicieux d’extraire cette classe et de la ranger dans un fichier à part, un fichier qui ne contiendra que cette classe. Cela contribue à la modularité de votre application. C’est plus facile à maintenir et à tester. Chaque classe est indépendante des autres.

Le standard d’utilisation qu’il est vivement conseillé de suivre est de mettre chaque classe dans un fichier dont le nom sera exactement le nom de la classe, avec le suffixe .php (respectez les majuscules et les minuscules).

Exemple

La classe Produit sera sauvegardée dans un fichier appelé Produit.php.

On peut ensuite inclure ce fichier dans le script principal grâce à l’instruction include.

Syntaxe :

<?php 
include NomDeLaClasse.php 

Exemple

Sauvegardez la classe Produit dans le fichier Produit.php :

Créez un nouveau fichier avec VSCode.

Dans le fichier index.php, sélectionnez le code de la classe uniquement, copiez (touches [Ctrl] C), retournez dans le nouveau fichier créé, et collez (touches [Ctrl] V), en n’oubliant pas d’ajouter <?php en première ligne. Enfin, sauvegardez le nouveau fichier (touches [Ctrl] S) avec le nom Produit.php :

<?php 
 
// ici nous sommes dans le fichier Produit.php 
 
class Produit 
{ 
    private $nom="mon Produit"; 
    private $quantite=3; 
    private $prix=120; 
    private $rupture=false; 
 
    function __construct($nom,$quantite,$prix,$rupture=false) 
    { 
        $this->nom=$nom; 
        $this->quantite=$quantite; 
        $this->prix=$prix; 
        $this->rupture=$rupture; 
 
    } 
 
    function getNom() 
    { 
        return $this->nom; 
 
    } 
 
    function setNom($valeur) 
    { 
        if (!is_string($valeur)){ 
            echo "la propriété nom doit être un chaîne de caractères"; 
        } 
         else { 
            $this->nom=$valeur; 
        } 
 
    } 
 
    function getQuantite() 
    { 
        return $this->quantite; 
 
    } 
 
    function setQuantite($valeur) ...

L’héritage de classe

Certaines classes peuvent avoir des éléments en commun. Dans la logique de ne jamais dupliquer du code inutile, il est apparu la notion d’héritage entre classes.

L’héritage permet à une classe de posséder toutes les propriétés et les méthodes d’une autre classe, tout en ayant ses propres éléments supplémentaires.

L’héritage se définit avec le mot-clé extends.

Syntaxe :

Class ClasseFille extends ClasseMere 
{ 
... 
} 

Reprenons l’exemple de la classe Produit. Imaginons un produit qui se vend par lots. Ce produit est un peu différent du Produit standard. Lorsqu’on commande un produit par lot, on commande en une seule fois plusieurs unités d’un même produit.

Il est donc judicieux de créer une nouvelle classe ProduitParLots qui héritera de la classe Produit, mais qui contiendra une propriété supplémentaire : le nombre d’articles par lot ($nbArticlesParLot).

On peut créer cette classe dans le sous-dossier MesProduits comme la classe Produit. Créez le fichier Mesproduits/ProduitsParlots puis insérez-y le code suivant :

<?php 
namespace MesProduits; 
 
class ProduitParLots extends Produit 
{ 
    private $nbArticlesParLot; ...

La signature d’une méthode

La signature d’une méthode décrit les entrées et les sorties de la méthode.

Autrement dit, la signature indique le nombre de paramètres en entrée ainsi que le type des paramètres (string, integer, array, object...).

Il est possible, depuis PHP7, de préciser le type des paramètres en entrée et aussi le type de la méthode en sortie (type de la valeur du return).

Syntaxe :

 class NomDeMaClasse 
{ 
 
 
    ... 
    maPremiereFonction(type parametre,type paramètre…):type 
    { 
        ... 
    } 
 
 
} 

Le type devant chaque paramètre indique le type du paramètre et le :type derrière la déclaration de la fonction est le type du retour de la méthode ( si la méthode ne retourne pas de valeur, nous pouvons lui attribuer un type vide :void ou l’omettre).

Le fait d’ajouter les types permet un meilleur contrôle de l’utilisation des méthodes. Il est donc conseillé de le faire.

Exemple : dans la classe Produit, nouspouvons définir le type des paramètres du constructeur.

function __construct(string $nom, int $quantite, float $prix,  
                    ...

Redéfinition d’une méthode

Revenons à la redéfinition des méthodes.

Pour les méthodes autres que le constructeur, la méthode de la classe fille qui redéfinit la méthode de la classe mère doit avoir la même signature.

Dans notre exemple, il est possible de redéfinir les méthodes ajouterProduit() et supprimerProduit() dans la classe ProduitParLots afin de prendre en compte la propriété $nbArticlesParLots dans le calcul :

class ProduitParLots extends Produit 
{ 
    private $nbArticlesParLot; 
 
    function ajouterProduit() 
    { 
        $this->quantite+=$this->nbArticlesParLot; 
        if($this->quantite>0) $this->rupture=false; 
    } 
 
    function supprimerProduit() 
    { 
        $this->quantite-=$this->nbArticlesParLot; 
        if($this->quantite<=0){ 
            $this->quantite=0; 
            $this->rupture=true; 
        } ...

Portée des éléments dans les classes filles

Il existe un type de portée qui permet l’accessibilité des éléments de la classe mère dans les classes filles sans pour autant autoriser cet accès à l’extérieur : la portée protected.

Syntaxe :

class NomDeMaClasse 
{ 
 
    protected $maPremiereVariable=valeur ; 
    protected $maDeuxiemeVariable=valeur ; 
    protected maMethode() 
    { 
          ... 
    } 

Dans la classe Produit, par exemple, il est préférable de mettre les propriétés avec la portée protected, afin de pouvoir les réutiliser dans les méthodes de la classe ProduitParLots.

Voici les modifications dans la classe Produit :

<?php 
namespace MesProduits; 
class Produit 
{ 
 
    protected $nom="mon Produit"; 
    protected $quantite=3; 
    protected $prix=120; 
    protected $rupture=false; 
    ... 
} 

Cette fois, le script ne produit plus d’erreur et renvoie les bonnes valeurs :

images/5RI4.png

Redéfinition du constructeur de la classe mère

Le constructeur fonctionne différemment, à savoir qu’il est possible de redéfinir un constructeur n’ayant pas la même signature dans la classe fille.

Par exemple, dans la classe ProduitParLots, nous allons ajouter le paramètre $nbArticlesParLot, pour définir cette valeur à l’instanciation de l’objet. Ce paramètre n’existe pas dans la définition du constructeur de la classe mère Produit.

Le constructeur de la classe fille est prioritaire. Mais nous souhaitons aussi appeler le constructeur de la classe mère.

Pour éviter de dupliquer le code du constructeur de la classe mère dans celui de la classe fille, nous appelons ce constructeur à l’aide de l’opérateur de résolution de portée :: et du mot-clé parent.

Syntaxe :

class NomDeMaClasseFille 
{ 
    function __construct(parametres classe fille) 
    { 
      ... 
      // appel du constructeur de la classe mère 
      parent::construct(parametres classe mère) 
    } 
 
} 

Dans l’exemple, nous pouvons redéfinir le constructeur dans ProduitParLots. Voici cette fois le code complet de la classe ProduitParlots :

<?php 
namespace MesProduits; 
class ProduitParLots extends Produit 
{ 
 
    private $nbArticlesParLot; 
 
    function __construct(string $nom, int $quantite, int $nbArticlesParLot, 
                         float $prix,bool $rupture=false) 
    { 
 
        $this->nbArticlesParLot=$nbArticlesParLot; 
        parent::__construct($nom,$quantite,$prix,$rupture); 
 
    } 
 
    function ajouterProduit() 
    { 
 
        $this->quantite+=$this->nbArticlesParLot; 
 
        if($this->quantite>0)...

Les constantes et les variables « static »

Il existe deux autres types de variables que l’on peut inclure dans une classe : les constantes et les variables « static ».

1. Les constantes

Les constantes sont des éléments dont la valeur n’est définie qu’une seule fois.

Nous ne pouvons pas changer la valeur d’une constante au cours du script.

Les constantes s’utilisent pour définir des éléments de configuration fixes dans l’application.

Nous les écrivons de manière standard en majuscules, éventuellement séparées par le caractère _ (c’est la norme snake_case).

Syntaxe :

class Maclasse 
{ 
 
    const MA_CONSTANTE=valeur ; 
 
 
} 

Cette constante peut être utilisée dans les méthodes de la classe en se servant du mot-clé self et de l’opérateur de résolution de portée ::.

Notez la différence entre les instruction self et $this :

  • self fait référence à la classe dans laquelle nous travaillons.

  • $this fait référence à l’objet instancié en cours.

Cette nuance est très importante.

Quel que soit l’objet qui instancie la classe, l’élément self::CONSTANTE fait référence à la même valeur, incluse dans la classe elle-même.

$this fait référence à des variables intrinsèques à l’objet. Ces variables peuvent avoir des valeurs différentes selon les objets, ce qui n’est pas le cas de self, puisque nous sommes dans la classe commune.

Syntaxe du self :

class Maclasse 
{ 
 ...

Les classes abstraites et les interfaces

Nous n’irons pas plus loin sur l’étude du langage objet (bien qu’il y ait encore beaucoup à dire), mais une dernière notion est importante, d’autant plus qu’elle est utilisée dans Symfony : c’est la notion de classe abstraite et d’interface.

1. Les classes abstraites

Tout découle de l’héritage de classe, l’idée étant d’avoir des classes mères qui ne servent qu’à l’héritage.

Une classe abstraite est une classe qu’on ne peut pas instancier.

Elle est définie avec le mot-clé abstract.

Une classe abstraite peut contenir des méthodes abstraites. Les méthodes abstraites sont des méthodes qu’il est obligatoire de redéfinir dans la (ou les) classes filles.

Ces méthodes ne contiennent que des signatures, elles n’ont pas de contenu.

Syntaxe d’une classe abstraite :

abstract class Maclasse 
{ 
 
    // peut contenir des propriétés et des méthodes  
 
    abstract public function maFonction(parametres); 
 
} 

Une méthode ne peut être abstraite que si la classe est abstraite.

Dans notre exemple, la classe Produit peut dériver d’une classe abstraite qu’on appellera ProduitAbstract qui regroupera la structure générale de la classe Produit. 

Créons un sous-dossier de MesProduits que nous appellerons MesProduitsWithAbstract. 

Puis, créons un fichier ProduitAbstract.php dans ce sous-dossier et plaçons-y la classe abstraite MesProduits/MesProduitsWithAbstract :

<?php 
namespace MesProduits\MesProduitsWithAbstract; 
 
abstract class ProduitAbstract 
{ 
   const DEVISE="euros"; 
   static $nbProduits; 
   protected $nom; 
   protected $quantite; 
   protected $prix; 
   protected $rupture; 
 
   abstract function __toString(); 
    
   abstract  function ajouterProduit(); 
    
   abstract function supprimerProduit(); 
} 

Une classe abstraite permet de s’assurer de la structure des classes qui en héritent. C’est un bon moyen de concevoir une structure de base au départ et d’être sûr que toutes les classes qui seront créées la respecteront.

Nous allons faire un héritage de la classe Produit à partir de la classe abstraite ProduitAbstract.

Attention, il faut définir le use dans le fichier Produit.php pour pouvoir atteindre la classe ProduitAbstract :

<?php 
namespace MesProduits; 
use MesProduits\MesProduitsWithAbstract\ProduitAbstract; 
 
class Produit extends ProduitAbstract 
{ 
    function __construct(string $nom,int $quantite,float 
    $prix,bool $rupture=false) 
    { 
 
        $this->nom=$nom; 
        $this->quantite=$quantite; ...

Conclusion

Vous disposez maintenant de toutes les connaissances indispensables pour développer en PHP et surtout utiliser le framework Symfony. Il existe bien sûr d’autres notions en PHP qui n’ont pas été abordées pour ne pas alourdir l’ouvrage. Si vous souhaitez aller plus loin sur la programmation en PHP, nous vous conseillons de vous rendre sur le site : PHP the right way qui détaille de manière claire et précise toutes les notions PHP : https://www.phptherightway.com