Programmation orientée objet – Introduction en PHP

php programmation orientée objet

La POO (Programmation Orientée Objet) est un terme souvent perçu comme compliqué par les développeurs débutants.

Pourtant, ce concept est de plus en plus utilisé à la place du PHP procédural par les développeurs mais aussi dans les frameworks et les CMS. Ce chapitre est une introduction à la POO, qui, rassurez-vous, est en fait bien plus accessible et compréhensible que vous pourriez le penser.

01 – POO, qu’est-ce que c’est ?

La programmation orientée objet (POO) en PHP est un concept apparu avec la version 4 de PHP mais qui a réellement commencé à prendre de l’ampleur depuis la sortie de PHP 5. Elle consiste à représenter sous forme « d’objets » des formes d’entités informatiques qui ont la particularité d’interagir ensemble. La POO est une nouvelle méthode de travail un peu différente de celle que vous pouviez utiliser jusqu’à présent en PHP. Elle introduit un nombre important de termes à connaître tels que : objet, classe, attribut, méthode, etc…

02 – Les avantages de la Programmation Orientée Objet

On ne peut pas affirmer qu’une méthode de développement soit meilleure qu’une autre.
En effet, la programmation orientée objet et la programmation procédurale sont deux façons différentes de développer une application, le choix se faisant selon vos préférences. Cependant, la Programmation Orientée Objet apporte quelques avantages non négligeables et permet d’avoir :
– un code réutilisable : les objets créés peuvent servir de base pour d’autres objets. Cela permet de regrouper les objets similaires pour ne pas avoir à écrire plusieurs fois le même code. De plus, il est possible de réutiliser le code dans différents projets.
– un code modulaire : il est possible de regrouper les fonctions dans des genres de « namespaces » (aussi appelée espace de nommage). On peut définir deux classes différentes pour une même méthode qui aura ainsi un comportement différent. Aussi, il est facile de rajouter des éléments sans avoir à modifier tout le code.
– un code plus clair : le concept impose une nomenclature qui permet instinctivement d’avoir un code plus lisible et mieux organisé. Il permet aussi d’avoir un code plus compréhensible pour les autres développeurs amenés à reprendre votre code.

03 – Qu’est-ce qu’un objet ? 1/2

Les objets peuvent être comparés à des éléments de notre vie commune : une personne, un ballon, un ordinateur, une voiture, etc…
En fait, un objet est une représentation d’une chose matérielle ou immatérielle à laquelle on peut associer diverses propriétés et actions. Pour faire encore plus simple, un objet est un mélange de variables et de fonctions PHP ! D’ailleurs, chaque objet a accès au même ensemble de variables et de fonctions mais la valeur de chaque variable peut différer d’un objet à un autre.

04 – Qu’est-ce qu’un objet ? 2/2

Pour ce tutoriel, imaginons que notre objet est un véhicule. Il possède plusieurs propriétés telles qu’un nom, un prix, une puissance, une plaque d’immatriculation…
Toutes ces propriétés, propres à notre véhicule, définissent ses caractéristiques. Une fois dans le véhicule, nous pouvons faire plusieurs actions, comme démarrer, accélérer, freiner…
En Programmation Orientée Objet, toutes les propriétés et les actions d’un objet sont contenues dans ce aue nous appelons une classe.

05 – Qu’est-ce qu’une classe ?

Une classe est une représentation abstraite d’un objet. En fait, nous pouvons assimiler une classe à un moule grâce auquel nous allons créer autant d’objets que nous souhaitons. Ce moule permet de définir une structure commune à tous les objets. Une classe est composée de propriétés et d’actions, nommées respectivement attributs et méthodes qui correspondent en PHP à des variables et à des fonctions. Chaque objet créé à partir d’une classe possède automatiquement des attributs qui sont accessibles à partir des méthodes de la classe. Par exemple, notre classe « Véhicule » contient la méthode freiner() qui modifiera la vitesse de notre objet à partir du moment ou elle sera appelée.

06 – Qu’est-ce qu’une instance ?

Quand on crée un objet, on dit qu’on fait une instance de la classe. C’est à dire que l’on crée une version d’un objet à un moment donné. Il est possible de créer plusieurs instances d’une classe. On obtient ainsi plusieurs objets. Chaque instance possède les attributs et les méthodes de la classe. Toutes les instances d’une classe sont indépendantes les unes des autres, c’est à dire que des modifications sur l’une des instances d’une classe n’auront pas de répercussions sur les autres instances de cette classe. Il n’y a aucune communication entre les différentes instances et donc aucun lien entre les objets.

07 – Déclaration d’une classe

Nous allons déclarer une classe « Véhicule » qui permettra d’instancier autant d’objets que nous souhaitons. On définit une classe à l’aide du mot-clé « class » puis on ajoute son nom. La norme exige que la première lettre de la classe soit en majuscule. En PHP, il est assez simple de déclarer une classe. Voici le code nécessaire :
class Vehicule {
// Contenu de la classe
}

Créer un fichier « vehicule.class.php » et insérez le code ci-dessus. Par convention, le nom du fichier est composé du nom de la classe suivi de l’extension « .class.php ». Le fichier ne doit contenir qu’une seule classe. Sachez que pour la suite du tutoriel, nous allons déclarer nos attributs et nos méthodes entre les accolades de la classe.

08 – Créer des attributs 1/2

Une classe est composée de deux parties : les attributs et les méthodes. La première partie consiste à déclarer l’intégralité des attributs de la classe. Ces attributs sont des variables qui contiennent les caractéristiques de nos objets. Les attributs peuvent être déclarés comme étant publics, privés ou protégés (public, private ou protected).
Pour cet exemple nous déclarons les attributs de notre classe en private. Nous expliquerons un peu plus loin dans le tutoriel les trois niveaux de portée qui peuvent être appliqués à un attribut. Notez que deux classes différentes peuvent avoir les mêmes attributs sans créer de conflit pour autant.

09 – Créer des attributs 2/2

En suivant notre exemple de la classe « Vehicule », nous allons définir quelques attributs comme le modèle et la marque du véhicule mais aussi sa couleur, son prix, et son nombre de roues. Nous ajoutons un attribut vitesse pour connaître la vitesse du véhicule à un moment donné (Je vais utiliser des noms de variables en Français pour mon exemple mais sachez qu’il est mieux de les écrire en Anglais par convention et n’oubliez pas d’indenter votre code correctement).
class Vehicule {
private $modele;
private $marque;
private $couleur;
private $prix;
private $vitesse;
private $nbRoues;
}

Nous pouvons aussi initialiser les valeurs des attributs de la classe comme ci-dessous :
class Vehicule {
private $modele = '911';
private $marque = 'Porsche';
private $couleur = 'noir';
private $prix = 20000;
private $vitesse = 0;
private $nbRoues 4;
}

A chaque nouvelle instance de la classe « Vehicule », les objets auront tous les mêmes caractéristiques. Les objets créés seront des Porsche 911 de couleur noire dont le prix est de 20 000 € avec vitesse de 0 km/h (normal, le véhicule n’a pas encore démarré).

10 – Les constantes

Il est possible de déclarer des constantes propres à une classe. La différence avec la programmation procédurale réside dans le fait qu’une constante est déclarée avec le mot-clé « const » au lieu d’utiliser la fonction define(). Par exemple :
class Toto {
const AGE = 25;
}

11 – Créer des méthodes 1/2

La deuxième partie d’une classe est composée de méthodes qui sont ni plus ni moins que des fonctions PHP. Les méthodes correspondent aux actions qu’un objet peut réaliser. Elles peuvent prendre des paramètres et retourner des valeurs. Comme les attributs, les méthodes disposent des mêmes types de portée (public, private et protected). En général, elles sont appelées depuis une instance d’un objet et possèdent donc le type public. Notez que deux classes peuvent avoir les mêmes méthodes sans créer de conflit. Pour notre classe « Vehicule », nous allons permettre à nos objets de réaliser plusieurs actions : démarrer, accélérer et freiner :
class Vehicule {
private $modele;
private $marque;
private $couleur;
private $prix;
private $vitesse = 0;
private $nbRoues = 4;
public function freiner($vitesseEnMoins){}
public function demarrer(){}
public function accelerer($vitesseEnPlus){}
}

12 – Créer des méthodes 2/2

Au sein des méthodes, il est possible de faire appel aux autres éléments (attributs, constantes et méthodes) d’une classe lors d’une instance à l’aide de la pseudo-variable $this qui est une référence de l’objet en cours. Si nous ajoutons l’opérateur -> à $this, l’ensemble permet d’accéder aux attributs et de faire appel aux méthodes au sein de la classe. Pour notre exemple, nous allons créer une méthode freiner() qui permet de réduire la vitesse du véhicule en fonction de la vitesse précisée en argument :
public function freiner($vitesseEnMoins) {
$this->vitesse = max(0, $this->vitesse - $vitesseEnMoins);
}

A l’aide de la fonction max() qui permet de retourner la valeur maximum d’un tableau, nous déterminons la nouvelle valeur de la vitesse en cours du véhicule. La valeur 0 est ajoutée pour faire en sorte que la vitesse soit toujours supérieure ou égale à 0. En effet, si nous demandons au véhicule de freiner de 30km/h alors qu’il roule à 20km/h, il lui est impossible de rouler à -10km/h. Dans ce cas précis, la valeur 0 sera supérieure à la valeur -10 et la fonction max() retournera une vitesse de 0.

13 – Créer un objet (une instance d’une classe)

Nous l’avons vu précédemment : quand on crée un objet, on dit que l’on fait une instance d’une classe. L’instanciation d’un objet est semblable à l’appel d’une fonction à une exception près. Le nom de la classe à instancier doit être précédé du mot-clé « new », comme ci-dessous :
$vehicule = new Vehicule();
Cela signifie que nous avons instancier un nouvel objet. L’objet retourné est stocké dans une variable afin d’être utilisé ultérieurement.

14 – Le principe de l’encapsulation

Il est possible de contrôler la portée et les accès des attributs et des méthodes d’une classe. Pour des raisons de sécurité, le principe de la Programmation Orientée Objet prévoit qu’un utilisateur de la classe doive se contenter d’utiliser des méthodes en ignorant l’utilisation directe des attributs. Comme nous l’avons expliqué lors de la définition d’une classe, chaque objet créé possède automatiquement des attributs qui doivent être accessibles à partir des méthodes de la classe. On appelle ce principe « l’encapsulation des données » dont le but est de ne pas pouvoir accéder aux données de l’objet directement, mais via des méthodes appelées « getters » et « setters ». Des explications sont fournies un peu plus loin dans le tutoriel.

15 – La portée des attributs et des méthodes 1/3

Il existe trois niveaux de portée : publique, privée et protégée. Le niveau de portée public est le comportement par défaut. Il permet d’avoir accès aux attributs et aux méthodes depuis n’importe quel endroit de l’application. Sachez qu’il n’est pas nécessaire de préciser le niveau de portée public lors de la déclaration d’un attribut ou d’une méthode. Par exemple, créons une classe « Toto » qui contient l’attribut $hello et la méthode getHello() avec accès public :
class Toto {
public $hello = 'Hello world !';
function getHello() {
return 'Hello WORLD !';
}
}

A présent, faites un test en insérant les quelques lignes de code suivantes sur le ou les fichiers de votre choix et vous vous apercevrez que la portée public permet d’accéder aux attributs et aux méthodes :
$toto = new Toto();
echo $toto->hello; // Affiche "Hello World !"
echo $toto->getHello() // Affiche "Hello WORLD !"
$toto->hello = "Salut tout le monde !";
echo $toto->hello; // Affiche "Salut tout le monde !"

16 – La portée des attributs et des méthodes 2/3

A l’inverse, le niveau de portée private restreint l’accès et l’utilisation des attributs et des méthodes au sein même de la classe. C’est à dire que les éléments seront visibles uniquement par la classe et qu’aucun accès depuis l’extérieur ne sera autorisé. Par exemple, créons une classe « Toto » qui contient l’attribut privé $hello et la méthode public getHello() :
class Toto {
private $hello = 'Hello world !';
public function getHello() {
return $this->hello;
}
}

Dans le cas où un utilisateur tente d’accéder à un élément privé en dehors de la classe, PHP retournera l’erreur fatale suivante :
$toto = new Toto();
echo $toto->getHello(); // Affiche "Hello World !"
echo $toto->hello; // Affiche l'erreur fatale "Cannot Access private property"

17 – La portée des attributs et des méthodes 3/3

Le niveau d’accès protected est associé aux concepts d’héritage que nous allons voir prochainement dans ce tutoriel. Comme pour l’accès privé, il est interdit de faire appel à des attributs et à des méthodes protected à l’extérieur de la classe, mais il est possible de les utiliser au sein des classes dérivées. Dans notre exemple, la classe « Camion » est dérivée de la classe « Vehicule » :
class Vehicule {
protected $vitesseMax = 130;
}

class Camion extends Vehicule {
public function __construct() {
$this->vitesseMax = 90;
}

public function getVitesseMax() {
return $this->vitesseMax;
}
}

La classe « Camion » contient les notions __construct() et extends qui seront expliquées ultérieurement dans le tutoriel. Dans cet exemple, il faut retenir que l’attribut protégé $vitesseMax de la classe « Vehicule » est inaccessible depuis l’extérieur de la classe, mais qu’il est possible de l’utiliser et de le modifier au sein de la classe « Camion » qui est dérivée de la classe « Vehicule ».
Si nous tentons d’accéder à l’attribut $vitesseMax en dehors de la classe « Vehicule » ou « Camion », PHP déclenchera l’erreur fatale suivante :
$camion = new Camion();
echo $camion->vitesseMax; // Affiche une erreur fatale

18 – Les getters 1/2

Comme nous l’avons précisé précédemment, le principe d’encapsulation prévoit que les attributs d’une classe soient accessibles et modifiables à partir des méthodes de la classe. Pour récupérer la valeur des attributs à l’extérieur de la classe, nous utilisons une série de méthodes nommées getters. Nous devons créer une méthode pour chaque attribut. Le nom d’une méthode dite getter doit commencer par « get », suivi du nom de l’attribut avec une majuscule comme première lettre. Complétons notre classe « Vehicule » avec la liste des getters à placer juste après le constructeur :
public function getModele(){return $this->modele;}
public function getMarque(){return $this->marque;}
public function getCouleur(){return $this->couleur;}
public function getPrix(){return $this->prix;}
public function getVitesse(){return $this->vitesse;}
public function getNbRoues(){return $this->nbRoues;}

19 – Les getters 2/2

Récupérons la valeur des attributs grâce aux méthodes. Voici un exemple d’utilisation :
$data = array('marque' => 'Porsche', 'couleur' => 'noire');
$maPorsche = new Vehicule($data);
echo 'Mon véhicule est une ' . $maPorsche->getMarque() . ' et il est de couleur ' . $maPorsche->getCouleur();

Ici, nous avons fait une instance de la classe « Vehicule » et nous avons assigné la valeur « Porsche » à l’attribut marque et la valeur « noire » à l’attribut couleur. Grâce aux méthodes getMarque() et getCouleur() nous avons modifié et affiché les valeurs des attributs marque et couleur. Cet exemple affichera : « Mon véhicule est une Porsche et il est de couleur noire ».

20 – Les setters 1/2

Vous venez d’apprendre que les getters permettent de récupérer la valeur des attributs en dehors de la classe. De la même façon que les getters, il existe une série de méthodes appelées setters qui permettent de modifier la valeur des attributs à partir de l’extérieur de la classe. Ajoutez les lignes suivantes après les getters de la classe « Vehicule » :
public function getModele(){return $this->modele;}
public function setMarque($v){return $this->marque = $v;}
public function setCouleur($v){return $this->couleur = $v;}
public function setPrix($v){return $this->prix = $v;}
public function setVitesse($v){return $this->vitesse = $v;}
public function setNbRoues($v){return $this->nbRoues = $v;}

21 – Les setters 2/2

Une fois que les setters sont ajoutés dans la classe, il est possible d’assigner de nouvelles valeurs aux attributs d’un objet :
$maPorsche = new Vehicule(array('marque' => 'Ferrari'));
$maPorsche->setMarque('Porsche');
echo $maPorsche->getMarque(); // Affiche Porsche

Dans cet exemple, nous faisons une instance de la classe « Vehicule » et assignons la valeur « Ferrari » à l’attribut marque. Grâce à la méthode setMarque(), nous modifions la valeur de l’attribut « marque » et affichons la nouvelle valeur stockée dans l’objet.

22 – Le constructeur d’une classe 1/2

Lorsque nous créons une instance d’une classe, PHP permet d’initialiser un objet à l’aide d’une méthode spécifique. Il s’agit de la méthode __construct() qui est automatiquement exécutée chaque fois qu’un objet est créé. On parle alors de « constructeur ». Pour notre premier exemple, créons une classe « Toto » composée d’un constructeur qui retourne une chaîne de caractères :
class Toto {
function __construct() {
return 'On a fait une instance de la classe';
}
}

23 – Le constructeur d’une classe 2/2

Comme il s’agit d’une fonction, elle peut prendre elle aussi des paramètres. pour mieux comprendre l’utilité d’un constructeur, il faut savoir que nous pouvons initialiser les attributs d’une classe lors d’une instance en fonction des paramètres qui lui sont fournis. Ajoutez le code suivant juste après la liste des attributs de notre classe « Vehicule » :
public function __construct($data = array()) {
if ($data) {
foreach ($data as $key => $value) {
$this->$key = $value;
}
}
}

Ce constructeur permet d’assigner une valeur aux attributs lors d’une instance de la classe en fonction des paramètres fournis. L’array $data doit être un tableau associatif dans lequel la clé correspond au nom de l’attribut.
Voici un exemple d’utilisation :
$data = array (
'modele' => '911 GT 500',
'marque' => 'Porsche',
);
$vehicule = new Vehicule($data);
echo $vehicule->getMarque() . ' ' . $vehicule->getModele(); // Affiche Porsche 911 GT 500

24 – Les méthodes statiques 1/2

La Programmation Orientée Objet permet d’avoir accès à une méthode d’une classe sans devoir l’instancier. Pour cela, la méthode doit être déclarée comme étant « statique » (ou static). Ce nouveau niveau de portée permet aussi d’avoir accès à la méthode en dehors de la classe. On parle alors de « méthodes de classe » puisqu’elles n’appartiennent pas à un objet en particulier. Cela signifie aussi que les méthodes statiques sont communes à l’ensemble des objets d’une même classe. Pour préciser qu’une méthode est statique, il suffit d’ajouter « static » avant la déclaration de la méthode. Attention, toutes les méthodes statiques n’ont pas accès aux attributs de la classe. Ainsi, la variable $this n’existera jamais !
Voici un exemple de déclaration d’une méthode « statique » :
class Toto {
static function bonjour() {
return 'Bonjour';
}
}

Pour faire appel à une méthode statique d’un objet en dehors de la classe, nous devons utiliser l’opérateur :: précédé du nom de la classe. Voici un exemple d’utilisation avec notre classe « Toto » :
echo Toto::bonjour(); // Affiche "Bonjour"

25 – Les méthodes statiques 2/2

Si vous souhaitez faire appel à la méthode statique au sein d’une méthode comportant une portée publique ou private de la classe, nous devons utiliser l’opérateur :: précédé de la mention self. Pour être plus précis, self est une résolution de portée dont l’accès est réservé à la classe elle même. Ci-dessous, un exemple d’utilisation :
class Toto {
public function parler(){
return 'La méthode bonjour() dit' . self::bonjour();
}

static function bonjour() {
return 'Bonjour';
}
}

Cet exemple affichera « La méthode bonjour() dit bonjour ».

26 – Accéder à une constante

De la même façon que les méthodes statiques, les constantes d’une classe sont accessibles à l’aide de l’opérateur :: et il n’est pas nécessaire d’instancier la classe pour accéder à la valeur de la constante. Par exemple, créons une classe « Toto » qui contient une constante nommée « AGE » :
class Toto {
const AGE = 25;
}

Tout comme les attributs ou les méthodes avec niveau d’accès public, la valeur de la constante peut être récupérée de n’importe quel endroit de l’application :
echo Toto::AGE; // Affiche "25"

27 – Le concept de l’héritage 1/3

Le concept de l’héritage en Programmation Orientée Objet est fondamental. Il permet de réutiliser les attributs et les méthodes d’une classe dite « parent » pour construire ou faire évoluer des classes dérivées, également nommées classes « enfants ». On dit que les classes « enfants » héritent des caractéristiques de la classe « parent ». Ce procédé permet d’éviter de réécrire des attributs ou des méthodes existantes dans plusieurs classes alors qu’il suffit de les réadapter selon les besoins sans modifier la classe d’origine dont elles seraient dérivées. Pour préciser à PHP qu’une classe hérite d’une autre, il faut utiliser le mot-clé « extends ».

28 – Le concept de l’héritage 2/3

Étant donné que la classe « Camion » hérite des attributs et des méthodes de la classe « Vehicule », nous pouvons utiliser toutes les méthodes déjà créées dans la classe « Vehicule » pour récupérer les valeurs des attributs. Pour cet exemple, créons la classe « Camion » qui hérite de la classe « Vehicule » :
class Camion extends Vehicule {
private $nbRoues = 8;
public function demarrer(){
$this->vitesse += 30;
}
}

Ci-dessous, un exemple d’utilisation de la classe « Camion » :
$camion = new Camion('Poids lourd', 'Renault', 'jaune');
$camion->demarrer();
echo 'Un camion qui possède ' . $camion->getNbRoues() . ' roues et de couleur ' . $camion->getCouleur() . ' roule à la vitesse de ' . $camion->getVitesse() . ' Km/h';

Cet exemple affiche : « Un camion qui possède 8 roues et de couleur jaune roule à la vitesse de 30 Km/h ».

29 – Le concept de l’héritage 3/3

Dans notre exemple, nous avons déclaré de nouveau l’attribut $nbRoues pour lui assigner une nouvelle valeur. Concernant la méthode demarrer(), nous l’avons redéclarée pour qu’elle puisse modifier la vitesse du camion. On dit qu’on a surchargé un attribut et une méthode de la classe « Parent ». C’est à dire que l’on peut déclarer des attributs et des méthodes de la classe « Parent » dans la classe « Enfant » pour modifier leur contenu. Dans ces cas précis, les attributs et les méthodes de la classe « Enfant » sont prioritaires sur celles de la classe « Parent ».

30 – Accès aux méthodes d’une classe « parent »

En cas de besoin, il est possible de faire appel aux caractéristiques d’une méthode de la classe « Parent » si elle est aussi définie dans la classe « Fille ». Pour cela, il faut utiliser parent:: devant la méthode de la classe « Parent » pour la manipuler à partir de la classe enfant. Voici un exemple d’utilisation avec une classe « Parent » et une classe « Fille » :
class Parent {
public function afficher() {
return 'Contenu de la classe Parent';
}
}

class Fille extends Parent {
public function afficher() {
$texteParent = parent::afficher();
return 'Contenu de la classe Fille et ' . $texteParent;
}
}

Dans cet exemple, la méthode afficher() de la classe « Fille » récupère le contenu de la même méthode de la classe « Parent » et retourne un nouveau texte. Affichons les résultats des deux méthodes pour voir la différence :
$parent = new Parent();
$fille = new Fille();
echo $parent->afficher(); // Affiche "Le contenu de la classe Parent"
echo $fille->afficher(); // Affiche "Le contenu de la classe fille et le contenu de la classe Parent"

31 – Conclusion

Ce tutoriel a été l’occasion de vous dévoiler les bases essentielles nécessaires à la compréhension de la Programmation Orientée Objet.
Cependant, ce concept est vaste et beaucoup de points comme les interfaces, le polymorphisme ou les classes abstraites n’ont pas été abordés ici. C’est pourquoi, pour aller plus loin, nous vous conseillons grandement de vous procurer un ouvrage complet que nous avons trouvé au meilleur prix en cliquant ici.

N’hésitez pas à nous poser toutes vos questions sur le blog du Petit Dev.