• 10 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

Paperback available in this course

course.header.alt.is_certifying

Got it!

Last updated on 8/21/23

Spécialisez vos objets avec les espaces de noms

Vous avez vu les fondamentaux de la programmation orientée objet avec l'héritage. Dans cette partie, nous allons ajouter deux cordes supplémentaires à votre arc ! Il est temps pour vous d'apprendre à exploiter les objets, et de les structurer à l'aide des méthodes de conception qui rendent la programmation orientée objet si intéressante : l'héritage horizontal et la composition. Avant de pouvoir vraiment se pencher dessus, je dois vous montrer comment séparer votre code.

Découvrez les espaces de noms

Une des règles à garder en tête lorsque l'on conçoit des classes, c'est de limiter leur rayon d'action. Une classe ne devrait posséder qu’une seule responsabilité. Il en va de même pour les méthodes qui la composent. Ça évite d'avoir des méthodes trop complexes, d'introduire des bugs, c'est plus facile de les tester et de les faire évoluer.

Du coup, parfois il se trouve que deux classes utilisées pour une action similaire et différente à la fois existent dans votre code.

Commençons à partir d’un  Message  pour un forum et d’un  Message  pour une messagerie interne : deux classes différentes avec le même nom.

Sauf qu'en PHP, il est interdit d'avoir deux classes portant le même nom !

<?php

declare(strict_types=1);

class Message
{}

class Message
{}

Tester ce code 

Ce code vous donnera une erreur ! Le choix facile, ce serait de les renommer... Ahahah ! 😂 Il n'y a rien de pire que de nommer les choses ! NON, plus facile : on va encapsuler nos classes dans des "espaces" réservés.

On encapsule dans l'espace   Forum  pour la première, et l'espace   Messenger  pour la seconde. Ces espaces concernent surtout le nom de nos classes, c'est pour ça que ça s'appelle les espaces de noms. Il permettent de regrouper des classes sous un même nom, et surtout d’empêcher les ambiguïtés. :)

Utilisez les espaces de noms

Les espaces de noms existent dans plusieurs langages. En PHP, il faut utiliser le mot clé  namespace  suivi du nom de cet espace et d'un point-virgule :

<?php

declare(strict_types=1);

namespace Forum;
class Message
{}

namespace Messenger;
class Message
{}

Toutes les classes déclarées sous le   namespace  seront considérées comme lui appartenant. Dès qu'un nouveau namespace est déclaré, les classes suivantes seront dans ce dernier.

Pour faire référence à une classe en particulier, vous devez préfixer son nom par son espace de noms :

<?php

declare(strict_types=1);

namespace Forum;

class Message
{}

namespace Messenger;
class Message
{}

$forumMessage = new \Forum\Message;
$messengerMessage = new \Messenger\Message;

var_dump($forumMessage::class);
var_dump($messengerMessage::class);

Tester ce code

Quels sont ces     autour de   Forum  et   Messenger  ?

Ici nous exprimons le ‘namespace’ avec des comme séparateurs. Eh oui, c'est vrai qu'il y en a un devant aussi. Par défaut, PHP possède un espace de nom global représenté par cet anti-slash. Depuis le début de ce cours, vous l'utilisez sans le savoir ! Si vous ne précisez aucun ‘namespace’, PHP considère que vous faites référence au ‘namespace’ global.

Avec ceci en tête, à votre avis, que fait PHP si on crée une instance de  DateTime  à la suite des  Message  ? 🤔

<?php

declare(strict_types=1);

namespace Forum;

class Message
{}

namespace Messenger;
class Message
{}

$forumMessage = new \Forum\Message;
$messengerMessage = new \Messenger\Message;
$date = new DateTime();

var_dump($forumMessage::class);
var_dump($messengerMessage::class);

Tester ce code

Qu’est-ce que cette erreur ?

Rappelez vous, PHP pense qu'on est dans l'espace de nom  Messenger  . Or,  DateTime  se situe toujours dans l'espace global. Pour y faire référence, on doit rajouter l'anti-slash devant :

$date = new \DateTime();

‌Essayez avec le code précédent !

Il y a une autre technique pour déclarer les classes dans les espaces de noms, c'est d'encapsuler les espaces de noms avec les accolades. Mais alors se pose une autre contrainte : lorsqu'un espace de noms est déclaré dans un fichier, tout le code de ce fichier doit faire partie d'un espace de noms. 

Eh oui, dans l'exemple précédent, tout ce qui suit   namespace Messenger;    fait partie de l'espace de noms  Messenger  . Ce qui laisse penser deux choses. La première, c'est que la ligne 15 aurait pu être :

$messengerMessage = new Message;

Si je ne précise rien, c'est forcément dans l'espace de noms courant. Je vous laisse constater par vous-même. :) La seconde, c'est qu'avec les accolades, le code suivant ne marche pas :

<?php

declare(strict_types=1);

namespace Forum {
   class Message
   {}
}

namespace Messenger {
   class Message
   {}
}

$forumMessage = new \Forum\Message;
$messengerMessage = new \Messenger\Message;

var_dump($forumMessage::class);
var_dump($messengerMessage::class);

Tester ce code

Mais pourquoi ce code ne marche pas ?

Vous devez encapsuler les lignes 15 à 19 dans un namespace. S'il s'agit du namespace global, alors il suffit de ne pas nommer l'espace de noms :

<?php

declare(strict_types=1);

namespace Forum {
   class Message
   {}
}

namespace Messenger {
   class Message
   {}
}

namespace {
   $forumMessage = new Forum\Message;
   $messengerMessage = new Messenger\Message;
  
   var_dump($forumMessage::class);
   var_dump($messengerMessage::class);
}

Tester ce code

Encore une chose sur les espaces de noms. Dans notre exemple, il y a un seul niveau, mais on peut avoir des espaces à plusieurs niveaux ! Par exemple :

<?php

namespace App\Domain\Messenger {
   class Message
   {}
}

namespace {
   $messengerMessage = new App\Domain\Messenger\Message;
   var_dump($messengerMessage::class);
}

Tester ce code

Et il n'est pas rare de voir des espaces de noms à 6, 8 niveaux ou plus. Mais attention : dans votre code ça va vite être moche et difficile à lire. C'est pourquoi vous pouvez préciser en avance à quel espace de noms vous faites référence, lorsque vous utilisez le nom d'une classe. On dit qu'on "importe" une classe.

On importe quoi ?

On n'importe rien du tout, en fait. Le terme n'est pas super bien choisi. En fait, on précise pour l'ensemble de l'espace de noms courant que la classe à utiliser appartient à un autre espace de noms, et ça vaudra sauf si on précise un autre espace de noms en entier.

Pour importer une classe d'un espace de noms différent, on utilise le mot clé  use  suivi du FQCN complet :

<?php

namespace App\Domain\Messenger {
   class Message
   {}
}

namespace {
   use App\Domain\Messenger\Message;
  
   $messengerMessage = new Message;
   var_dump($messengerMessage::class);
}

Tester ce code

Nous avons vu les deux syntaxes : avec et sans accolades. En pratique, nous préférons utiliser la syntaxe sans accolade. Une pratique courante est de définir l’espace de nom dans lequel on se trouve au début du fichier, puis de préciser les classes provenant des autres espaces de nom (avec le mot-cléuse) en dessous. Ensuite, on y met notre code. 

Exercez-vous

Dans le cadre du projet MatchMaker, il serait bon de séparer nos classes dans des espaces de noms dédiés, et de les organiser de manière logique. Partons du principe que nos espaces de noms seront préfixés par   App\MatchMaker  pour désigner toutes les classes appartenant à notre application MatchMaker.

Ajoutez autant d'espaces de noms que nécessaire, et placez les classes logiquement sous ces espaces.

Vous trouverez le code sur la branche P3C1, et la correction sur la branche P3C1-correction :)

En résumé

  • Vous pouvez avoir plusieurs classes du même nom en les cloisonnant dans un espace de noms.

  • Déclarer un espace de noms s'effectue à l'aide du mot clé namespace.

  • Un espace de noms peut être de plusieurs niveaux séparés par un \.

  • Par défaut, PHP utilise un espace de noms global représenté par un \.

  • Lorsque vous exploitez un espace de noms spécifique pour une classe, vous pouvez le déclarer pour tout l'espace de noms courant avec le mot clé use.

Les développeurs sont des malins. Avez-vous remarqué la façon d'écrire les espaces de noms, et la façon d'écrire des chemins de répertoire ? C’est similaire ! Ils ont donc exploité ça pour charger automatiquement des fichiers à partir du FQCN. 

Voyons ensemble dans le prochain chapitre comment faire !

Example of certificate of achievement
Example of certificate of achievement