Depuis PHP 5, le modèle objet présenté par PHP est complet : définition de classes, extension de classes, héritage, visibilité des méthodes et attributs, classes et méthodes abstraites, interfaces, etc.

Une classe est une structure de données créée par le développeur pour représenter une abstraction du "monde" qu'il doit gérer dans son développement. Par exemple pour une gestion de production, le "monde" sera composé d'abstractions comme des types de machine outil, des matières premières, des produits finis, etc. Pour un jeu, le "monde" sera composé d'abstractions comme des types de personnages, des armes, des lieux, des véhicules, etc.

Une abstraction aura des caractéristiques particuliéres et pourra effectuer des actions (ou y être soumises). Dans la structure de données classe, une caractéristique est appelée un attribut (ou une propriété) et la réalisation d'une action est appelée une méthode. Ce ne sont ni plus ni moins que des variables et des fonctions, avec la particularité qu'elles sont définies dans une classe et non dans un programme (ou un script).

Pour passer de l'abstraction à la "réalité" on va à partir d'une classe créer des objets. On appelle celà instancier une classe. A la fin de cette opération on a donc un objet avec les éléments caractériques de sa classe et qui va pouvoir effectuer (ou subir) les actions définies par sa classe. La valeur des attributs de l'objet sera personnalisée en fonction des caractéristiques propres de l'objet. Les méthodes quant à elle ne sont pas personnalisables et leur valeur (une fonction) est immutable.

Par exemple une classe Voiture aura un attribut couleur. La valeur de l'attribut couleur pour l'objet Cadillac Eldorado sera "rose bonbon" alors que celle pour l'objet 2CV sera "bleu".
Malgré leurs différences d'aspect et de caractéristiques, les 2 objets issus de la classe Voiture auront des méthodes identiques, comme par exemple démarrer, accélerer, freiner.

Les classes de cette forme de programmation orientée objet ne sont rien d'autre que l'application des idées de Platon et de sa théorie des formes.

Il existe d'autres formes de programmation orientée objet, notamment celle basée sur l'utilisation de prototypes pour représenter les abstractions. On trouve ce paradigme dans des langages comme JavaScript.

### Exemple

Ce chapitre sera illustré par l'utilisation de classes liées à une activité marchande de vente sur Internet. Les produits vendus seront des d'abord des guitares puis nous étendrons notre catalogue à d'autres produits concernant les guitares (méthodes, partitions, cordes, etc).

L'exemple ci-dessous est un exemple simplifié d'une classe représentant un modèle de guitare proposé à la vente sur notre site.

Exemple : syntaxe de base
<?php ob_start(); require('bib_fonctions.php'); class Guitare { private $modele; private $prix; private $cordes; private $remise = 0; public function __construct($p1, $p2, $p3) { $this->modele = $p1; $this->prix = $p2; $this->cordes = $p3; } public function setRemise($taux) { if (is_numeric($taux) && estEntre($taux, 0, 100)) { $this->remise = $taux; } } public function getPrix() { $rem = ceil($this->prix * $this->remise / 100); return $this->prix - $rem; } public function decrire() { echo '<h4>Instance de la classe ', __CLASS__, '</h4>', $this->modele, '<br>', $this->cordes, ' cordes<br>', $this->getPrix(), ' &euro;'; } } // Fin de la classe Guitare htmlDebut('La classe Guitare'); $guitare = new Guitare('Guild D120', 639, 6); $guitare->decrire(); $guitare->setRemise(30); htmlInfo('Nouveau prix : '.$guitare->getPrix()); htmlFin(); ?>

L'usage veut que le code correspondant à une classe soit mis dans un fichier qui ne contient que ce code (exemple : `guitare.class.php`), puis que ces fichiers soit inclus dans le script principal (comme le fichier `bib_fonctions.php`). Dans le cadre de ce tutoriel, par souci de simplification, le code des classes sera directement inclus dans le script principal.

### L'opérateur ->

Contrairement aux autres langages orientés objet, PHP n'utilise pas la syntaxe à point pour travailler avec les objets, leurs attributs et leur méthodes.
Rappel : dans PHP l'opérateur point (`.`) est l'opérateur de concaténation.

Pour accéder aux attributs et aux méthodes d'un objet, on utilise en PHP l'opérateur `->`.

l'opérateur ->

### Définir une classe

définir une classe

Le nom d'une classe doit commencer par une lettre ou le caractère _ (underscore). Les caractères suivants peuvent être des lettres, des nombres, le caractère _.

Une règle d'usage veut que le nom d'une classe commence par une lettre majuscule.

### Définir des attributs

définir des attributs

La définition d'un attribut commence avec un des mots-cléss `private`, `public` ou `protected`. Ce mot-clé définit la visibilité de l'attribut, c'est à dire depuis où l'attribut peut être vu/accédé (plus d'infos plus loin dans l'encapsulation).

Dans sa définition, le nom de l'attribut doit être précédé du signe `$`, comme les variables dans PHP.

Le nom d'un attribut doit commencer par une lettre ou le caractère _ (underscore). Les caractères suivants peuvent être des lettres, des nombres, le caractère _.

Les noms d'attributs sont sensibles aux majuscules et aux minuscules. Par exemple `mon_attribut` est différentde `Mon_Attribut` ou de `MON_attribut`.

On peut affecter une valeur à un attribut au moment de sa définition. La valeur peut être de n'importe quel type supporté par PHP. Il faut que cette valeur soit une valeur constante, c'est à dire qu'elle ne peut pas une référence à une variable, à une autre propriété, à un objet, ou au résultat de l'évaluation d'une fonction.

définir un attribut avec une valeur par défaut

Il est possible de regrouper les attributs avec une même visibilité lors de leur définition.

regrouper la définition des attributs

Dans notre exemple, la classe Guitare aura 4 attributs, tous privés :
- `modele` : le modèle de la guitare (exemple Guild D120, Fender Villager),
- `prix` : le prix de la guitare en euros,
- `cordes` : le nombre de cordes, soit 4, 6 ou 12,
- `remise` : le taux de remise éventuel sur le prix.

### Définir des méthode

définir des méthodes

La définition d'une méthode commence avec un des mots-cléss `private`, `public` ou `protected`. Ce mot-clé définit la visibilité de la méthode, c'est à dire depuis où la méthode va pouvoir être invoquée (plus d'infos plus loin dans l'encapsulation).

Les méthodes ne sont rien d'autres que des fonctions et comme telles elles sont soumises aux mêmes règles que les autres fonctions du langage pour le nommage, les paramètres, les renvois de valeur (voir page Notions de base - Les fonctions et suivantes).

Dans notre exemple, la classe Guitare aura 4 méthodes, toutes publiques :
- `__construct` : la méthode constructeur de la classe,
- `setRemise` : pour mettre à jour le taux de remise,
- `getPrix` : pour obtenir le prix de vente (prix - remise éventuelle),
- `decrire` : pour afficher une description de la guitare.

classe Guitare décrite avec le formalisme UML

Par souci de simplification les méthodes ne seront pas décrites dans les exemples. Dans un développement réel, la description et les commentaires de méthodes sont obligatoires, par exemple avec le formalisme PHPDoc.

### Le mot-clé `$this`

le mot-clé `$this`

Le mot-clé `$this` s'utilise uniquement dans le code à l'intérieur des méthodes d'une classe.

Dans la classe, `$this` représente l'objet instancié avec cette classe. `$this` permet de manipuler des attributs et d'invoquer les méthodes offertes.

Quand `$this` est utilisé pour travailler avec un attribut, le nom de l'attribut ne doit pas être précédé du caractère `$` comme c'est le cas lors de sa définition.
On écrit donc `$this->attribut` et pas `$this->$attribut`

En PHP, `$this` doit être utilisé explicitement (ie `$this->attribut = 10` ou `$this->methode()`). Il n'y a pas de mécanisme qui permettrait une référence implicite (ie `attribut = 10` ou `methode()`).

### Instancier des objet

instancier un objet

La création d'un objet à partir d'une classe s'appelle l'instanciation. Un objet est l'instance d'une classe.

L'instanciation se fait avec l'opérateur `new`, suivi du nom de la classe à instancier.

Si des paramètres doivent être passés au constructeur de la classe (voir plus loin Constructeur et destructeur), le nom de la classe doit être suivi d'une paire de parenthèses entourant ces paramètres (exemple : `$objet = new Classe($p1, $p2);`).
Si la classe n'a pas de constructeur ou si son constructeur n'attend pas de paramètre, les parenthèses sont facultatives (exemple : `$objet = new Classe;`).

La fonction get_class() permet de connaître la classe dont l'objet est l'instance.
A l'intérieur d'une classe, la "constante magique" PHP `__CLASS__` peut être utilisée pour connaître le nom de la classe.

Exemple : syntaxe de base
<?php ob_start(); require('bib_fonctions.php'); // Définition de la classe Guitare class Guitare { // Définition des attributs private $modele; private $prix; private $cordes; private $remise = 0; // Constructeur public function __construct($p1, $p2, $p3) { $this->modele = $p1; $this->prix = $p2; $this->cordes = $p3; echo '<hr>Une nouvelle '.__CLASS__.' a été créée<hr>'; } } // Fin de la classe Guitare htmlDebut('La classe Guitare'); // création d'un nouvel objet instance de la classe Guitare $g = new Guitare('Guild D120', 639, 6); htmlInfo('$g est une instance de la classe '.get_class($g)); htmlFin(); ?>

### Invoquer des méthodes

Lors de l'instanciation d'un classe, l'opérateur `new` renvoie la référence (ie l'adresse) mémoire de l'objet qu'il vient de créer (exemple `$variable = new Classe;`). En général, la référence renvoyée par l'opérateur `new` est affectée dans une variable qui constitue une variable référence "pointant" sur l'objet créé.

On peut ensuite utiliser cette variable pour invoquer les méthodes de l'objet avec l'opérateur `->` (exemple `$variable->methode();`).

Exemple : syntaxe de base
<?php ob_start(); require('bib_fonctions.php'); // Définition de la classe Guitare class Guitare { // Définition des attributs private $modele; private $prix; private $cordes; private $remise = 0; // Constructeur public function __construct($p1, $p2, $p3) { $this->modele = $p1; $this->prix = $p2; $this->cordes = $p3; } // Méthode public function setRemise($taux) { if (is_numeric($taux) && estEntre($taux, 0, 100)) { $this->remise = $taux; } } // Méthode public function getPrix() { $rem = ceil($this->prix * $this->remise / 100); return $this->prix - $rem; } // Méthode public function decrire() { // Normalement il faudrait protéger les valeurs avec // htmlentities. Pas fait pour simplifier l'exemple. echo '<h4>Instance de la classe ', __CLASS__, '</h4>', $this->modele, '<br>', $this->cordes, ' cordes<br>', $this->getPrix(), ' &euro;'; } } // Fin de la classe Guitare htmlDebut('La classe Guitare'); // création d'un nouvel objet instance de la classe Guitare $guitare = new Guitare('Guild D120', 639, 6); // Invocation de la méthode décrire $guitare->decrire(); // Invocation de la méthode setRemise $guitare->setRemise(30); // Invocation de la méthode getPrix htmlInfo('Nouveau prix : '.$guitare->getPrix()); htmlFin(); ?>

### Objet et notion de référence

Exemple : objet et notion de référence
<?php ob_start(); require('bib_fonctions.php'); // Définition de la classe Guitare class Guitare { // Définition des attributs public $prix; }// Fin de la classe Guitare htmlDebut('La classe Guitare'); $g1 = new Guitare; // $g1 est une référence sur l'objet instance // de la classe Guitare $g1->prix = 500; $g2 = $g1; // $g2 reçoit une copie de la référence contenue dans $g1. // $g2 et $g1 sont 2 références pointant sur le même objet // instance de la classe Guitare. $g2->prix = 1000; htmlInfo('Nouveau prix : '.$g1->prix); function fct($g){ // Notez l'absence du &. // Le paramètre $g est transmis par valeur. // La fonction reçoit une copie de la référence // (ou de l'adresse) mémoire de l'objet. $g->prix = 1500; } fct($g2); htmlInfo('Nouveau prix : '.$g1->prix); htmlFin(); ?>

### Exercice : Définir et utiliser une classe

la classe Livre

Ecriver la classe `Livre` dont le modèle est ci-contre.

L'attribut `pages` est un nombre de pages.
L'attribut `cat` est une catégorie qui peut être "Méthode", "Partition", "Biographie" ou "Autre".

La méthode `decrire()` doit afficher les détails d'un livre (ie la valeur de tous les attributs).

Vous devez instancier 3 livres avec les informations suivantes :

Titre | Auteur | Nb Pages | Prix | Cat.
Débutant Guitare Acoustique | Rébillard | 70 | 17 | Méthode
Les accords de guitare | Carpentier | 160 | 4.90 | Méthode
Guitar Play Along Neil Young | Leonard | 50 | 21.90 | Partition

affichage du détail de 3 livres

Une solution possible

Exercice : la classe Livre
<?php ob_start(); require('bib_fonctions.php'); // Définition de la classe Livre class Livre { // Définition des attributs private $titre; private $auteur; private $pages; private $prix; private $cat; // Constructeur public function __construct($p1, $p2, $p3, $p4, $p5) { $this->titre = $p1; $this->auteur = $p2; $this->pages = $p3; $this->prix = $p4; $this->cat = $p5; } // Méthode public function decrire() { // Normalement il faudrait protéger les valeurs avec // htmlentities. Pas fait pour simplifier l'exemple. echo '<h4>Instance de la classe Livre</h4>', $this->titre, ' - ', $this->auteur, ' - ', $this->pages, ' pages - ', $this->prix, ' &euro; - ', $this->cat, '<hr>'; } } // Fin de la classe Livre htmlDebut('La classe Livre'); // création d'un nouvel objet instance de la classe Livre $livre1 = new Livre('Débutant Guitare Acoustique', 'Rébillard', 70, 17, 'Méthode'); // Invocation de la méthode decrire $livre1->decrire(); $livre2 = new Livre('Les accords de guitare', 'Carpentier', 160, 4.90, 'Méthode'); $livre2->decrire(); $livre3 = new Livre('Guitar Play Along Neil Young', 'Leonard', 50, 21.90, 'Partition'); $livre3->decrire(); htmlFin(); ?>