Un peu d’histoire
Dans PHP antérieur à 5.3 (2009), toute classe que vous définissez vivait au même niveau global que les autres classes.
Classe User
classe Contact
classe StripeBiller
–ils sont tous ensemble dans l’espace de noms global.
Cela peut sembler simple, mais cela rend l’organisation difficile, c’est pourquoi les développeurs PHP ont commencé à utiliser des traits de soulignement pour séparer leurs noms de classe. Par exemple, si je développais un package appelé “Cacher”je pourrais nommer la classe Mattstauffer_Cacher
pour le différencier de celui de quelqu’un d’autre Cacher
–ou Mattstauffer_Database_Cacher
pour le différencier d’une API cacher.
Cela fonctionnait correctement, et il y avait même des normes de chargement automatique qui séparaient les traits de soulignement dans les noms de classe pour les dossiers du système de fichiers ; Par exemple, Mattstauffer_Database_Cacher
serait supposé vivre dans le fichier Mattstauffer/Database/Cacher.php
.
Un chargeur automatique est un morceau de code qui fait en sorte qu’au lieu d’avoir à
require
ouinclude
tous les fichiers contenant vos définitions de classe, PHP sait où trouver vos définitions de classe en fonction d’une convention particulière.
Mais c’était assez désordonné et se terminait souvent par des noms de classe comme Zend_Db_Statement_Oracle_Exception
et pire. Heureusement, en PHP 5.3, de vrais espaces de noms ont été introduits.
Les bases des espaces de noms
Les espaces de noms sont comme une structure de répertoires virtuels pour vos classes. Donc class Mattstauffer_Database_Cacher
pourrait devenir class Cacher
dans le Mattstauffer\Database
espace de noms :
<?php
class Mattstauffer_Database_Cacher {}
est maintenant:
<?php namespace Mattstauffer\Database;
class Cacher {}
Et nous y ferions référence ailleurs dans l’application comme Mattstauffer\Database\Cacher
.
Un vrai exemple
Prenons Karani – c’est un CRM avec une composante financière, donc il suit les donateurs et les reçus, entre autres choses.
fixons Karani
comme notre espace de noms de niveau supérieur (un peu comme le dossier parent – généralement nommé d’après votre application ou votre package). Cela peut avoir des classes liées aux contacts et d’autres liées à la facturation, nous allons donc créer un sous-espace de noms pour chacune, Karani\Billing
et Karani\Contacts
.
Faisons une classe ou deux dans chacun :
<?php namespace Karani\Billing;
class Receipt {}
<?php namespace Karani\Billing;
class Subscription{}
<?php namespace Karani\Contacts;
class Donor {}
Donc, nous imaginons une structure de répertoires comme celle-ci :
Karani
Billing
Receipt
Subscription
Contacts
Donor
Référencer d’autres classes dans le même espace de noms
Ainsi, si un Abonnement peut envoyer un Reçu, il est facile de s’y référer :
<?php namespace Karani\Billing;
class Subscription
{
public function sendReceipt()
{
$receipt = new Receipt;
}
}
Depuis Receipt
est dans le même espace de noms que Subscription
vous pouvez simplement vous y référer comme vous le feriez si vous n’utilisiez pas d’espaces de noms.
Référencer d’autres classes dans différents espaces de noms
OK, mais que se passe-t-il si je veux faire référence à un reçu à l’intérieur d’un donateur ?
<?php namespace Karani\Contacts;
class Donor
{
public function sendReceipt()
{
// This won't work!
$receipt = new Receipt;
}
}
Vous l’avez deviné : cela ne fonctionnera pas.
Nous sommes dans le Karani\Contacts
espace de noms, donc quand nous avons écrit new Receipt
PHP suppose que nous parlons de Karani\Contacts\Receipt
. Mais cette classe n’existe pas, et ce n’est pas ce que nous recherchons.
Ainsi, vous obtiendrez un Class Karani\Contacts\Receipt not found
erreur.
Vous pourriez être tenté de le modifier pour dire à la place $receipt = new Karani\Billing\Receipt
— mais même cela ne fonctionnera pas. Puisque nous sommes dans le Karani\Contacts
espace de noms en ce moment, il voit quoi que ce soit vous écrivez comme étant relatif à l’espace de noms dans lequel vous vous trouvez. Donc, cela essaierait de charger une classe nommée Karani\Contacts\Karani\Billing\Receipt
qui n’existe manifestement pas non plus.
Use
blocs et noms de classe complets
Au lieu de cela, vous avez deux options :
D’abordvous pouvez le faire précéder d’une barre oblique pour créer son FQCN (Fully Qualified Class Name) : $receipt = new \Karani\Billing\Receipt;
qui envoie le signal à PHP pour s’échapper de l’espace de noms actuel avant de rechercher cette classe.
Si vous précèdez le espace de noms complet avec une barre oblique, créant le FQCN, vous pouvez vous référer à cette classe n’importe où dans votre application sans vous soucier de votre espace de noms actuel.
Ou, Deuxièmetu peux use
la classe en haut du fichier, puis référencez-la simplement comme Receipt
:
<?php namespace Karani\Contacts;
use Karani\Billing\Receipt;
class Donor
{
public function sendReceipt()
{
$receipt = new Receipt;
}
}
Comme vous pouvez constater, use
importe une classe d’un espace de noms différent dans cet espace de noms afin que nous puissions nous y référer plus facilement. Une fois que vous avez importé la classe, chaque fois que vous faites référence Receipt
dans cette classe, il supposera que vous pointez vers la classe importée.
Crénelage
Mais, et si vous aussi avoir un Receipt
classe dans votre actuel espace de noms ? Que faire si votre classe a besoin d’accéder aux deux Karani\Contacts\Receipt
et Karani\Billing\Receipt
?
Vous ne pouvez pas simplement importer le Karani\Billing\Receipt
class, ou vous ne pourrez pas utiliser les deux – ils auront tous les deux le même nom dans cette classe.
Au lieu de cela, vous devrez l’aliaser. Vous pouvez changer le use
déclaration à quelque chose comme use Karani\Billing\Receipt as BillingReceipt;
. Vous avez maintenant créé un alias pour la classe, puis vous pouvez faire référence à la classe importée en tant que BillingReceipt
tout au long de votre classe.
Chargement automatique PSR-0/PSR-4
Vous connaissez l’analogie de dossier que je viens d’utiliser ci-dessus ?
C’est facile de penser à vos cours de cette façon, mais il y a en fait pas toute connexion inhérente entre vos espaces de noms et la structure de vos fichiers. Sauf si vous utilisez un chargeur automatique, PHP n’a aucune idée où ces classes vivent en fait dans votre structure de répertoires.
Heureusement, PSR-0 (désormais obsolète) et PSR-4 sont des normes de chargement automatique qui mappent en fait vos espaces de noms sur de vrais dossiers. Donc, si vous utilisez PSR-0 ou PSR-4 – ce qui est extrêmement probable si vous utilisez Composer ou n’importe quel framework moderne – et un chargeur automatique compatible, vous pouvez supposer que les classes sont dans des dossiers.
Compositeur et chargement automatique PSR-4
Alors, disons que je veux le Karani
espace de noms pour vivre dans mon src
dossier.
Voici ma structure de dossiers pour un projet générique indépendant du framework :
app
public
src
Billing
Contacts
vendor
Comme vous pouvez le voir, le src
dossier représente le Karani
espace de noms de niveau supérieur. Étant donné que j’utilise Composer comme chargeur automatique, tout ce que j’ai à faire pour que mon application charge automatiquement mes classes est d’apprendre à Composer comment mapper les espaces de noms aux dossiers. Faisons cela en utilisant PSR-4.
je vais ouvrir composer.json
et ajoutez une section de chargement automatique PSR-4 :
{
"autoload": {
"psr-4": {
"Karani\\": "src/"
}
}
}
Vous pouvez donc voir : le côté gauche est l’espace de noms que nous définissons (notez que vous devez échapper les séparateurs de barre oblique ici en les doublant), et le côté droit est le répertoire.
Conclure.
Comme vous pouvez le voir, il se passe beaucoup de choses ici, mais c’est vraiment assez simple : 98 % du temps, vous allez travailler avec un ensemble de classes structuré PSR-4 et chargé automatiquement par Composer.
Ainsi, 98 % du temps, vous pouvez vérifier votre composer.json
, déterminez où se trouve la racine de l’espace de noms de niveau supérieur et supposez que vous aurez alors une carte un à un de votre espace de noms et des dossiers/fichiers de ce répertoire. Fait.
Et rappelez-vous : la prochaine fois que vous aurez Class SOMETHING not found
vous devez probablement vous rappeler de l’importer avec un use
déclaration en haut de votre dossier.