les arcanes de php5
Article, PHP

Les arcanes d’OOP dans PHP5

Cet article explique : Comment utiliser les fonctionnalités avancées offertes par l’OOP dans PHP5.

Ce qu’il faut savoir : Notions en PHP et quelques bases en programmation orientée objet.

Le changement majeur qui a marqué le passage de PHP de sa version 4 à sa version 5 est avant tout l’ajout complet du support du paradigme Objet. Et cela non seulement afin d’apporter plus de fonctionnalités au langage mais également pour en améliorer les performances et profiter ainsi de toute la puissance de PHP. Dans cet article, nous allons explorer quelques une de ces nouvelles fonctionnalités qui nous semblaient intéressantes, au travers de quelques exemples simples. Mais avant de commencer, on va admettre que vous êtes à l’aise avec la programmation orientée objet et que vous savez ce qu’est une classe, une instance, une méthode, etc. Si ce n’est pas le cas, je vous recommande de vous mettre à jour afin de mieux comprendre la suite de l’article.
Sans plus tarder, accrochez-vous, c’est parti!

1 Public, Private ou Protected ?

En OOP, les mots clés Public, Private et Protected permettent de définir le type d’accessibilité (ou encapsulation) des méthodes et des attributs d’une classe, c’est-à-dire quelle visibilité vous voulez donner à vos méthodes et attributs. Ainsi:

  1. Public : autorise à être accédé ou modifié par n’importe quel code et depuis n’importe où. A noter que ce type est celui par défaut de PHP, c’est-à-dire que si vous ne mettiez pas de type devant vos méthodes ou attributs, ils seront donc considérés comme publiques. Et cela dans le but de garder une certaine compatibilité avec la version 4 de PHP. C’est une habitude qu’on vous déconseille!
  2. Private : autorise uniquement l’accès et la modification d’une méthode ou d’un attribut depuis la classe elle-même. Il est interdit d’y faire appel depuis l’extérieur! Et de toute façon, cela provoquera une erreur fatale de type T_PRIVATE.
  3. Protected : autorise l’accès et la modification depuis la classe elle-même ou depuis n’importe quelle autre classe ayant héritée de celle-ci. C’est une solution intermédiaire entre un accès privé et un accès public.

Il faut savoir que le choix de ces contrôles d’accès est très important lorsqu’on travaille à plusieurs ou
lors de la programmation d’une brique logicielle. Vous devez bien choisir le bon type d’accès afin de
contrôler au mieux l’encapsulation de vos objets.

2 C’est une affaire d’héritage!

En développement logiciel, lorsque l’on souhaite caractériser un problème donné sous forme de classes d’objets, on constate qu’assez souvent plusieurs classes se retrouvent avec les mêmes propriétés ou méthodes. Et en tant que développeur, on préfère éviter ce type de situation, et pour cela on va essayer de privilégier une modélisation sous forme de catégorie et sous catégorie. Cette relation peut être expliquée avec la notion dites d’héritage. Si on veut caractériser par exemple un véhicule, ou plus précisément une voiture, on peut dire que l’objet qui modélise une 4L appartient à la classe Voiture qui elle même dérive de la classe Vehicule. On dit aussi que la classe Voiture hérite de la classe Vehicule: ce qui implique que la classe fille Voiture a accès à toutes les propriétés et méthodes publiques ou protégée de Vehiclue. Voici ce que cela donne en code:


class Vehicule {
    protected $nombre_de_places;
    public function avancer(){ … }
    public function reculer(){ … }
}
class Voiture extends Vehicule{
    private $marque;
    public function avancer(){ … }
    public function demarrer(){ … }
}

Pour définir une relation d’héritage en PHP, on utilise le mot-clé extends lors de la déclaration de la classe fille. D’après le code de l’exemple plus haut, la classe Voiture hérite de toutes les méthodes publiques ou protégées, donc dans notre cas: avancer() et reculer(), ainsi que tous les attributs publiques et protégés: $nombre_de_place. Cependant, on remarque que la classe fille redéfinit la méthode avancer(), ce qui veut dire que la méthode héritée de la classe Vehicle sera remplacée.

4 Accès aux méthodes parentes

Lorsqu’une classe fille veut accéder aux méthodes de la classe mère, il suffit d’utiliser la notation statique avec le mot-clé parent; ainsi la syntaxe parent::une_methode() permet d’appeler la méthode une_methode() de la classe mère.


class Vehicule {
    public function une_methode(){ … }
}
class Voiture extends Vehicule{
    public function une_autre_methode(){
        // …
        parent::une_methode();
        // …
    }
}

5 Notion d’héritage strict

En PHP, toute méthode redéfinie doit être compatible avec la méthode précédente, on parle alors d’héritage strict. C’est-à-dire que le nombre de paramètres obligatoires de la méthode fille doit être inférieur ou égal au nombre de paramètres possible de la méthode mère; cependant, le nombre de paramètres possible de la méthode fille doit quant à lui être supérieur ou égal au nombre de paramètres possibles de la méthode mère! Afin d’illustrer cette contrainte, prenons l’exemple ci-dessous d’une
méthode qui a trois paramètres obligatoires sur cinq, elle peut être remplacée par une méthode qui a un paramètre obligatoire et cinq facultatifs. C’est assez simple, non?


class Vehicule {
    public function super_methode($a, $b, $c='', d$=1, $e=''){ … }
}
class Voiture extends Vehicule{
    public function super_methode($a, $b='', $c=0, $d=1, $e=''){ … }
}

Note: Vous avez la possibilité d’utiliser la fonction func_get_args() qui doit absolument être utilisée à l’intérieur d’une méthode et qui vous rend un tableau contenant tous les paramètres passés à la méthode.

6 Règles de définition ?

En dérivant une classe, on peut vouloir redéfinir une méthode ou changer la valeur d’un attribut de la classe mère. Cependant, cette redéfinition n’est pas la même pour chacun des trois niveaux d’accessibilité.

Règle pour les niveaux Privé et Protected

La redéfinition des méthodes ou attributs publics suit une règle très simple: si un attribut ou méthode publiques sont redéfinis dans la classe fille, ils doivent être publics et c’est la dernière définition qui sera prise en compte!


class Vehicule {
    public $nombre_de_places = 4;
}
class Voiture extends Vehicule{
    public $nombre_de_places = 2;
}
// instanciation
$porsche = new Voiture();
echo $porsche->nombre_de_places;
// affiche 2

Or, si les méthodes ou attributs sont protégés, la règle diffère un peu: les nouvelles redéfinitions doivent être de même niveau ou peuvent être publiques.

Cas particulier des méthodes privées

La logique que suit la redéfinition des méthodes et des attributs privés est toute autre. En effet, le but ici est qu’il ne faut pas que la classe fille accède aux implémentations privées de classe parente. C’est pour cela, que si vous redéfinissez, par exemple, une méthode privée, PHP considère alors qu’il y a deux méthodes portant le même nom dans la classe. Dans ce cas là, si c’est la classe parent qui appelle cette méthode privée, alors c’est la première définition qui sera prise en compte (la définition de la
classe mère); par contre si c’est classe fille qui appelle cette méthode, ce sera la seconde définition qui
sera utilisée.

Évidement, cette situation est une source sûre d’erreurs, et donc pour des soucis de maintient ou tout simplement de relecture de code, je vous conseille d’éviter de redéfinir les méthodes privées!

7 Des méthodes très … magiques

Dans PHP5, on trouve également ce que l’on appelle les méthodes magiques; ce sont en effet, des méthodes réservées par PHP et commençant par un __ (un double tiret bas). Leur particularité est qu’elles sont automatiquement exécutées en réponse à certains évènements PHP.
Nous allons essayer d’expliquer quelques unes d’entres elles, et si vous êtes intéressés par les autres je vous prropose de visiter le lien suivant pour plus d’informations http://php.net/manual/fr/language.oop5.magic.php.

La méthode __construct()

La méthode __construct() est sans doute la plus connue et la plus utilisée, et j’ajouterais même la plus recommandée. En OOP en général, cette méthode correspond au constructeur d’une classe, et le rôle de tout bon constructeur c’est de s’exécuter lorsque sa classe est instanciée. Et c’est notamment dans le constructeur qu’on doit initialiser les attributs de la classe.


class Vehicule {
    protected $nombre_de_places;
    public function __construct(){
        $this->nombre_de_places = 4;
    }
}

Lorsqu’on a une classe fille qui souhaite accéder au constructeur de la classe mère, il suffit d’utiliser la notation statique parent::Ma_class() que nous verrons plus en détails dans la suite de cet article. Voici un exemple en code:


class Vehicule {
    public function __construct(){ … }
}
class Voiture extends Vehicule{
    public function __construct(){
        parent::Vehicule();
        // …
    }
}

La méthode __destruct()

La méthode __destruct() est l’opposé de __construct, car en effet elle est exécutée lorsqu’un objet est détruit, soit explicitement par le développeur ou parceque l’objet n’est plus utilisé. Vous vous demander sûrement à quoi peut-elle vraiment servir, puisque PHP s’occupe de nettoyer la mémoire? Et bien, supposons par exemple que l’on veuille écrire des données dans un fichier de log, il est important de bien libérer les ressources allouées que l’on a pu resérver pendant l’exécution de notre programme. Voici le code correspondant à cette situation:


class Log {
    public function __construct(){
        $this->logfile_handle = fopen('/tmp/log.txt', 'a');
    }
    public function __destruct(){
        fclose($this->logfile_handle);
    }
}

Des méthodes de surcharge : __get(),__set() et __call()

Avant d’aller plus loin, il est primordial de rappeler la notion de surcharge en PHP; car en effet, le terme surchage n’a pas la même signification en PHP qu’en d’autres langages. Il ne s’agit pas de définir plusieurs prototypes différents d’une même méthodes car tout simplement ceci n’est pas très utile en PHP puisque les paramètres acceptent par défaut des données sans vérification de type.

En PHP, on trouve trois méthodes de surcharge (optionnelles) dont le rôle est d’intercepter les appels à des méthodes ou attributs non définis. Vous pouvez donc les utiliser afin de répondre à PHP et faire comme si ces méthodes ou attributs existaient.

Cependant, l’intérêt de la surcharge en PHP est de créer des objets d’interface qui ne savent pas quelles peuvent être les méthodes ou attributs appelés. On peut par exemple utiliser ce comportent pour interfacer un service web.

Affectation des attributs

Si vous implémentez la méthode __set(), cette méthode sera appelée à chaque fois qu’on essaye de modifier la valeur d’un attribut inexistant. Dans le cas contraire, le comportement par défaut sera adopté. Cette méthode doit accepter deux paramètres, le nom de l’attribut et sa valeur.


class MagicSet {
    public $attribut;
    public function __set($nom, $valeur){
        echo 'Affectation de ' . $nom . ' = ' . $valeur . ' .';
    }
}
// instanciation
$class = new MagicSet();
$class->attribut = 42;
echo $class->attribut;
// affiche 42
$class->nouveau_attribut = 42;
// affiche: Affectation de nouveau_attribut = 42 .

Lecture des attributs

De la même manière que pour la méthode __set(), vous pouvez utilisez la méthode __get() afin d’intercepter la lecture d’un attribut inexistant. Cependant, cette méthode ne doit accepter q’un seul paramètre, le nom de l’attribut.


class MagicGet {
    public $attribut;
    public function __get($nom){
        echo 'L\'attribut ' . $nom . ' n\éxiste pas!';
    }
}
// instanciation
$class = new MagicGet();
$class->nouveau_attribut;
// affiche: L’attribut nouveau_attribut n’éxiste pas!

L’une des utilités de ces deux méthodes est qu’elle vous permettent d’initialiser des attributs inexistants, ou si vous préférez: à la volé! Evidement, à utiliser avec la plus grande précaution.


class MagicGetAndSet {
    private $valeurs = array();
    public function __get($nom){
        if ( isset($this->valeurs[ $nom ]) )
        {
            return $this->valeurs[ $nom ];
        }else
        {
            exit('L\'attribut ' . $nom . ' est inexistant!');
    }
}
public function __set($nom, $valeur){
$this->valeurs[ $nom ] = $valeur;
}
}
// instanciation
$class = new MagicGetAndSet();
echo $class->nouveau_attribut;
// affiche: L'attribut nouveau_attribut est inexistant!
$class->nouveau_attribut = 42;
echo $class->nouveau_attribut;
// affiche: 42

8 Un monde statique!

En PHP, on a la possibilité de définir des attributs et méthodes statiques, c’est-à-dire qui sont accessibles sans avoir besoin d’instancier de classe.
Cependant, il ne faut pas oublier que lorsqu’on déclare des méthodes ou attributs statiques , on n’a pas accès à la pseudo-variable $this, qui n’est définie que quand on a un contexte d’exécution. Les propriétés statiques ne peuvent donc pas être appelées avec l’opérateur . En effet, l’appel à ces méthodes ou attributs statiques se fait en préfixant le nom des attributs ou méthodes par le nom de la classe. Depuis la version 5.3.0 de PHP, vous pouvez utiliser une référence de votre classe au lieu de son nom. L’appel statique est aussi utile lorsque vous devez appeler des constantes de classe.


class Foo {
    const CONST_FOO = 1024;
}
// Depuis PHP 5.3.0
$classname = 'Foo';
echo $classname::CONST_FOO;
// affiche 1024
echo Foo::CONST_FOO;
// affiche 1024

Voici un exemple complet qui vous montre comment on accède aux méthodes/attributs statiquement lorsqu’on a de l’héritage en plus:


class Foo {
    public static $my_static = 'foo';
    public function staticValue() {
        return self::$my_static;
    }
}
class Bar extends Foo {
public function fooStatic() {
return parent::$my_static;
}
}
echo Foo::$my_static;
// affiche : foo
$foo = new Foo();
echo $foo->staticValue();
// affiche : foo
echo $foo->my_static;
// affiche : Undefined "Property" my_static
echo $foo::$my_static;
// affiche : foo
// Depuis la version PHP 5.3.0
$classname = 'Foo';
echo $classname::$my_static;
// affiche : foo
echo Bar::$my_static;
// affiche : foo
$bar = new Bar();
echo $bar->fooStatic();
// affiche : foo

9 Conclusion

Nous avons donc exploré quelques unes des fonctionnalités en matière d’OOP de PHP5. Celles sont sont nombreuses et très diverses, je vous proposes de visiter le site officiel de PHP pour plus d’informations concernant toutes les possibilités offertes par ce langage.

Standard