Live Coding : PHP Orienté Objet - Namespace et Autoload

25 mai 2020 - : PHP Tutoriel Live-Coding - : 0 commentaire - Tutoriel PHP Live-Coding Orienté Objet

Visualisez les fichiers de cette série sur GitHub

Dernière modification le 26 mai 2020

Dans cette partie, nous allons voir comment organiser nos classes afin de simplifier la structure et éviter les conflits avec d'autres objets qui porteraient le même nom. Nous verrons également dans la 2ème partie comment mettre en place un chargement automatique de nos fichiers afin d'éviter de mettre de nombreuses lignes de "require".

Les espaces de nom (namespace)

Si deux développeurs différents appellent leurs objets de la même façon, nous aurons potentiellement des conflits lors de leur utilisation.

Les espaces de nom (namespace) permettent d'attribuer "virtuellement" des dossiers à nos classes.

Avant de créer ces "namespace", nous allons modifier légèrement la structure de nos dossiers et fichiers, comme ci-dessous.

Cette structure va nous permettre de faciliter la mise en place et le tri des différentes classes de notre projet.

Cependant, si un autre fichier contient une classe portant le même nom que notre "Compte", par exemple, nous aurons un problème.

Créons un dossier "Client" et une classe "Compte" à l'intérieur, ce qui donnera ceci

Comme vous pouvez le remarquer, nous aurons deux classes portant le même nom "Compte".

Nous aurions inclu les fichiers de cette façon

require_once 'classes/Client/Compte.php';
require_once 'classes/Banque/Compte.php';
require_once 'classes/Banque/CompteCourant.php';
require_once 'classes/Banque/CompteEpargne.php';

Ce qui va résulter en une erreur comme celle ci

Cannot declare class Compte, because the name is already in use

C'est là qu'entrent en jeu les espaces de noms.

Nous allons déclarer un "namespace" pour chacune des classes que nous créons.

Ce namespace ressemblera à un chemin et reprendra la structure de nos dossiers en partant du dossier "classes".

Nous allons commencer par nommer "App" puis suivre le chemin séparé par des "\".

Ainsi, en haut du fichier "classes/Clients/Compte.php" nous ajouterons

namespace App\Client;

En haut des fichiers du dossier "classes/Banque", nous ajouterons

namespace App\Banque;

A compter de cet instant, l'erreur a changé, notre serveur PHP n'arrive plus à trouver "CompteCourant".

Uncaught Error: Class 'CompteCourant' not found

Il s'agit d'une erreur "normale", il ne trouve pas la classe étant donné que nous n'avons pas donné son namespace.

Deux solutions s'offrent à nous.

La moins propre, ajouter le namespace lors de l'instanciation

$compte1 = new App\Banque\CompteCourant('Benoit', 500);

La plus utilisée, ajouter une ligne "use" en début de fichier pour indiquer dans quels namespaces rechercher les classes

use App\Banque\CompteCourant;

A noter que vous pouvez avoir plusieurs classes à charger dans le même namespace, dans ce cas vous pouvez utiliser autant de lignes "use" ou les cumuler sur la même

use App\Banque\{CompteCourant, CompteEpargne};

A noter que si vous avez deux classes qui portent le même nom, vous pouvez les renommer à la volée.

use App\Client\Compte as CompteClient;
use App\Banque\Compte as CompteBancaire;

L'autoload

Comme vous l'avez remarqué, nous aurons rapidement de nombreux fichiers à charger lors de l'utilisation des objets.

Nous allons mettre en place un système de chargement des fichiers à la demande.

En résumé, si le serveur PHP trouve une classe qu'il ne connaît pas, il va chercher le fichier correspondant et le charger pour nous.

La fonction spl_autoload_register

Tout repose sur la fonction PHP appelée spl_autoload_register. Cette fonction a pour rôle d'enregistrer une fonction qui sera appelée à chaque fois qu'une classe inconnue sera rencontrée. Ainsi, nous pourrons mettre en oeuvre un système qui permettra de chercher le fichier PHP correspondant à une classe et de le charger, si il existe.

Nous allons créer un fichier "Autoloader.php" dans le dossier classes. Ce fichier contiendra donc une classe "Autoloader" dans le namespace "App".

namespace App;

class Autoloader
{

}

Nous allons ensuite créer une méthode statique "register" qui permettra de l'activer sans instancier la classe.

Dans cette méthode, nous allons récupérer la classe par la constante magique "__CLASS__" et déclencher la méthode "autoload".

static function register()
{
    spl_autoload_register([
        __CLASS__,
        'autoload'
    ]);
}

La constante magique "__CLASS__" contient tout le chemin de la classe, incluant le namespace.

La méthode "autoload"

La méthode "autoload" devra donc retirer le début du namespace "App" puis remplacer les "\" par des "/" pour créer le chemin du fichier.

Ainsi, si nous cherchons à charger la classe "CompteCourant", son chemin complet incluant le namespace est "App\Compte\CompteCourant", nous retirons "App\", nous obtenons "Compte\CompteCourant", puis nous remplaçons les "\" par des "/" pour obtenir "Compte/CompteCourant". Il nous reste à inclure le dossier "classes" au début et le ".php" à la fin.

La méthode "autoload" ressemplera donc à

static function autoload($class){
    $class = str_replace(__NAMESPACE__. '\\','',$class);
    $class = str_replace('\\','/',$class); 
    if(file_exists(__DIR__ . '/' . $class . '.php')){
        require __DIR__ . '/' . $class . '.php'; 
    }
}

Il nous reste à modifier notre fichier "index.php" et à remplacer toutes les lignes "require_once" par

// On charge le fichier Autoloader
require_once 'classes/Autoloader.php';
// On charge la méthode statique
Autoloader::register();

Obtenir de l'aide

Pour obtenir de l'aide, vous pouvez accéder au serveur Discord pour une entraide par chat

Visualisez les fichiers de cette série sur GitHub

Partager

Partager sur Facebook Partager sur Twitter Partager sur LinkedIn

Commentaires

Ecrire un commentaire

Pas encore de commentaire

Ecrire un commentaire