La programmation orientée objet en PHP

hachesse

La programmation orientée objet apporte de nombreux avantages.

Comment bénéficier de ces avantages en PHP ?

- Titre : La programmation orientée objet en PHP

- Auteur : hachesse

- Parution : 31 octobre 2002

- Mise à jour : 8 décembre 2019

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2013 hachesse. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Classe, Attribut, Méthode, Constructeur

- III. Instanciation et manipulation des objets

- IV. Héritage

- V. Opérateur :: et parent

- VI. Durée de vie des objets, fonctions serialize() et unserialize()

- VII. Les fonctions magiques

- VIII. Conclusion

I - Introduction

Le but de cet article n'est pas de faire un cours sur la programmation objet en général, mais seulement sur son implémentation en PHP et les avantages qu'elle peut procurer.

Nous supposerons que les concepts liés à la programmation orientée objet sont déjà connus et seuls des rappels seront faits ici.

Par ailleurs, l'utilisation des classes en PHP4 étant légèrement différente de l'utilisation en PHP3, nous n'aborderons dans ce tutoriel que la syntaxe et les possibilités de PHP4.

II - Classe, Attribut, Méthode, Constructeur

Avant toutes choses, voyons comment se déclare une classe simple :

<?php
class myclass {
var $myvar;
function myclass($myparameter) {
$this->myvar = $myparameter;
}
function afficher() {
echo "myvar vaut : $this->myvar";
}
}
?>

Ce script montre comment déclarer une classe très simple, ne contenant qu'un seul attribut ($myvar), un constructeur, et une méthode (afficher()).

La déclaration d'une classe se fait par l'utilisation du mot clé class, suivi du nom de la classe. À partir de ce point, le moteur PHP sait que des objets de type myclass pourront être intentés et il sera capable de leur allouer un emplacement mémoire.

Les attributs sont des sortes de variables internes à l'objet qui ne sont accessibles qu'à travers celui-ci. Bien que PHP ne nécessite pas, en temps normal, de déclaration préalable des variables, dans la cadre d'une classe, il est préférable de la faire. La déclaration d'un attribut au sein d'une classe se fait par l'utilisation du mot clé var suivi du nom de l'attribut.

Les méthodes quant à elles, sont des fonctions internes à l'objet qui vont permettre d'agir sur les attributs de l'objet. La déclaration d'une méthode (ou fonction) à l'intérieur d'une classe se fait de la même façon que dans un script classique. On utilise pour cela le mot réservé function suivi du nom de la méthode. Ensuite, si la méthode requiert des paramètres, on les indiquera entre parenthèses. PHP étant un langage faiblement typé, vous noterez qu'il n'est pas nécessaire de spécifier le type de retour de la fonction.

Il existe aussi une méthode particulière appelée le constructeur de la classe. Cette méthode est particulière dans le fait qu'elle est automatiquement appelée lors de la création d'un objet (instanciation de la classe). Cette méthode permet d'initialiser l'objet à sa création en donnant par exemple des valeurs à chacun de ses attributs. Le constructeur d'une classe est donc une méthode qui porte le même nom que la classe dont elle est le constructeur.

III - Instanciation et manipulation des objets

La déclaration d'une classe n'étant pas suffisante pour utiliser les objets, il faut donc créer des objets avant de pouvoir s'en servir. La création d'un objet à partir d'une classe, s'appelle l'instanciation (un objet étant alors appelé une instance d'une classe). La création d'un objet permet plusieurs choses. La première, c'est réserver une place dans la mémoire centrale du serveur pour y stocker l'objet durant son utilisation. La seconde étant de donner un nom à cet objet. Enfin grâce au constructeur, la troisième étape sera d'initialiser cet objet (avec des valeurs par défaut ou passées en paramètres).

La création d'un objet à partir d'une classe se fait grâce au mot new suivi du nom de la classe (pas de l'objet) :

<?php
$myobject = new myclass(10);
$mytab[1] = new myclass(10);
?>

Ces deux exemples montrent comment créer des objets à partir de la classe myclass déclarée précédemment. Dans le premier cas, on crée un objet qui sera stocké dans une variable nommée $myobject et dans le deuxième cas, à l'indice 1 du tableau $mytab.

Notons également que lors de la création de ces objets, la valeur « 10 » a été passée en paramètre au constructeur. Cela permet d'affecter la valeur (10 en l'occurrence) à l'attribut $myvar de l'objet que l'on vient de créer.

Voici donc comment on déclare une classe et crée une instance. Il convient maintenant de voir comment se fait l'accès aux éléments (attributs et méthodes) qui composent un objet. Pour ce faire, on a recours à un ascenseur. Un ascenseur est constitué des deux caractères « - » et « > » mis l'un à la suite de l'autre (pour former une sorte de flèche « -> »). L'accès à un élément d'un objet se fait donc en précisant le nom de celui-ci (nom qui lui est donné lors de sa création) suivi de l'ascenseur puis enfin de l'élément voulu.

Ex. : $myobject->afficher() donne accès à la méthode afficher() de l'objet myobject. Dans le cas d'un appel à un élément à l'intérieur même de l'objet, le nom de l'objet n'étant pas connu, on fait appel à la variable spéciale $this qui désigne l'objet courant.

IV - Héritage

Le principal apport de la programmation objet est certainement la possibilité de réutiliser presque à volonté le code déjà écrit. Écrire une classe spécialisée à partir d'une classe générale est le meilleur moyen de réutiliser ce code déjà produit. Cette procédure s'appelle l'héritage et est introduite par le mot clé extends :

<?php
class myclass2 extends myclass {
var $myvar2 ;
function myclass2($myparameter, $myparameter2) {
$this->myvar = $myparameter;
$this->myvar2 = $myparameter2;
}
function afficher2($color) {
echo "<font color=\"$color\">myvar vaut : $this->myvar</font><br>";
echo "<font color=\"$color\">myvar2 vaut : $this->myvar2</font><br>";
}
}
?>

Ici nous venons de déclarer une classe fille myclass2 qui étend la classe mère myclass précédemment créée. Dans cette classe, nous avons ajouté un attribut myvar2 et une méthode afficher2($color) qui ne seront définis que dans cette classe. Nous avons également redéfini un constructeur myclass2 ($parameter, $parameter2) qui permet d'initialiser les deux attributs de l'objet lors de sa création :

<?php
$myobject2 = new myclass2(10, 20);
$myobject2->afficher2("red");
$myobject2->afficher();
?>

Ces trois lignes montrent comment utiliser un objet créé à partir d'une classe fille. Dans un premier temps, on crée une instance de la classe myclass2 que l'on stocke dans un objet nommé $myobject2, en attribuant les valeurs 10 et 20 aux attributs $myvar et $myvar2. Dans la deuxième ligne, on fait simplement appel à la méthode afficher2($color) définie dans mycalss2. La troisième quant à elle est plus intéressante. En effet, à aucun moment, la méthode afficher() n'apparaît dans la classe myclass2. Et pourtant, il est tout à fait possible d'utiliser cette méthode à cet endroit, car celle-ci a été héritée de la classe mère.

De la même manière, les attributs des classes mères sont également accessibles dans les classes filles. Nous avons déjà pu le remarquer dans le constructeur de la classe fille myclass2 où l'on a affecté une valeur à l'attribut $myvar qui n'est définie que dans la classe mère :

$this->myvar = $myparameter;

V - Opérateur :: et parent

Nous venons de voir qu'il était possible de définir des classes à partir d'autres classes. Dans l'utilisation des objets, il pourra aussi être utile de faire appel à certaines méthodes de certaines classes sans qu'aucun objet de cette classe n'ait été créé auparavant. Dans sa version 4, PHP permet d'effectuer ce genre de traitement sur des classes. On utilisera alors l'opérateur :: qui à la manière d'un ascenseur pour un objet permettra l'accès aux méthodes à travers un nom de classe :

<?php
class myDate {
var $day;
var $mounth;
var $year;
function mydate($day, $mounth, $year) {
$this->day = $day;
$this->mounth = $mounth;
$this->year = $year;
}
function printTodayDate() {
echo date("j/m/Y");
}
}

myDate::printTodayDate();
?>

Dans cet exemple, nous appelons la méthode printTodayDate() de la classe myDate sans qu'aucun objet de type myDate ne soit préalablement instancié. Bien sûr, une méthode de classe telle que celle-ci ne doit pas faire référence aux attributs qui ne seront valorisés que lors de la création effective de l'objet.

De façon similaire, on peut également faire appel aux méthodes de la classe mère d'un objet sans pour autant être obligé de créer un objet à partir de cette classe mère. Cela peut se révéler fort utile pour surcharger une méthode de base sans devoir reprendre tout le code de celle-ci. Reprenons l'exemple de nos deux classes myclass et myclass2 et ajoutons une méthode afficher() dans la classe fille myclass2 qui devra afficher la même chose que la méthode de la classe mère, mais également la valeur de $myvar2 :

function afficher() {
parent::afficher();
echo "myvar2 vaut : $this->myvar2";
}

Il aurait été tout à fait possible de réécrire totalement le code la méthode de la classe mère dans celle de la classe fille et d'y ajouter le code propre à la classe fille, d'autant plus que cela se fait très rapidement avec l'informatique. Cependant, cela se serait révélé la plus mauvaise des solutions. En effet, faire appel à la méthode de la classe mère et ne redéfinir que la partie de code spécifique à la classe fille permet de concevoir des programmes plus souples et plus modulaires.

Dans notre exemple, il suffira de changer la méthode de la classe mère pour que les modifications soit automatiquement répercutées dans la classe fille. Ainsi, le code suivant :

class myclass {
....
function afficher() {
echo "Affichage des attributs :";
echo "myvar vaut : $this->myvar";
}
}
....
$myobject2 = new myclass2 (10, 20);
$myobject2->afficher();

Affichera :

Affichage des attributs :
myvar vaut : 10
myvar2 vaut : 20

VI - Durée de vie des objets, fonctions serialize() et unserialize()

Comme toutes variables en PHP, la durée de vie d'un objet n'excède pas la durée d'exécution du script qui le crée. Dans ce cas, l'utilisation des objets n'est pas très avantageuse par rapport à des variables et des fonctions classiques. Cela est d'autant plus vrai que l'on ne peut pas passer des objets en paramètres grâce aux méthodes GET et POST. Alors pourquoi utiliser les objets s'ils ne permettent pas tous les avantages qu'ils présentent dans les autres langages orientés objet.

La réponse est simple. Il suffit de transformer notre objet, en une chaîne de caractères par exemple, pour que notre objet bénéficie de toutes les possibilités d'une variable « classique ». Pour cela, PHP dispose de deux fonctions serialize() et unserialize() qui permettent d'effectuer cette transformation :

<?php
$myobject = new myclass(10);
$mylinearobject = serialize($myobject);
$myobject2 = unserialize($mylinearobject);
$myobject2->afficher();
?>

Dans cet exemple, on crée un nouvel objet à partir de la classe myclass que l'on linéarise dans une variable. À cet instant, la variable $mylinearobject vaut : « O:7: »myclass« :1:{s:5: »myvar« ;i:10;} » qui est la représentation de notre objet. On peut alors appliquer la fonction inverse pour recréer l'objet dans la variable $myabject2 et en utiliser les méthodes.

VII - Les fonctions magiques

La fonction serialize() qui transforme les objets en une chaîne de caractères, le fait de façon trop « brutale » dans certains cas. En effet, il est possible que vos objets aient ouvert une connexion à une base de données et ne l'aient pas encore fermée. Dans ce cas, il est préférable (et même capital) de s'assurer que certaines opérations soient effectuées avant que l'objet ne soit effectivement linéarisé. C'est le rôle de la fonction magique __sleep(). Cette fonction, si elle existe dans l'objet sera automatiquement appelée par la fonction serialize() et permettra de fermer toutes vos connexions ou de nettoyer l'objet. La fonction __sleep() retourne obligatoirement un tableau contenant la liste des attributs à linéariser.

De façon similaire, la fonction magique __wakeup() est, si elle existe, automatiquement appelée par la fonction unserialize(). Elle pourra alors reconnecter l'objet à la base de données ou réinitialiser certains attributs :

<?php
class myclass {
...
function __sleep() {
$this->myvar = 50;
return array('myvar');
}

function __wakeup() {
$this->myvar = 100;
}
}
?>

Voici un exemple qui montre comment préparer les objets de la classe myclass à être linéarisés grâce à la fonction __sleep().

VIII - Conclusion

Les objets sont actuellement l'un des aspects du langage PHP qui concentrent le plus l'attention des développeurs du langage. On peut donc s'attendre dans les prochaines versions de PHP à une meilleure intégration et des possibilités encore plus étendues.

Ce tutoriel est à présent terminé. J'espère qu'il aura répondu à vos attentes. Si malgré les efforts de rédaction des erreurs, imprécisions ou autres fautes persistent dans cet article, merci de m'en faire part pour une correction plus rapide.