## Foire aux questions : ce qu'il faut savoir des espaces de noms

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

Cette FAQ est décomposée en deux sections : les questions courantes, et les points particuliers de l'implémentation, qui peuvent être utiles à la compréhension globale.

D'abord, les questions courantes.

1. Si je n'utilise pas d'espaces de noms, est-ce que je dois m'en soucier ?
2. Comment utiliser une classe globale ou interne depuis un espace de noms ?
3. Comment utiliser les classes d'espaces de noms, les fonctions ou les constantes dans leur propre espace ?
4. Comment est-ce qu'un nom comme `\mon\nom` ou `\nom` est résolu ?
5. Comment est-ce qu'un nom tel que `mon\nom` est résolu ?
6. Comment un nom de classe sans qualification, tel que `nom`, est résolu ?
7. Comment une fonction sans qualification ou une constante de nom `nom` est résolue ?

Voici les points particuliers de l'implémentation, qui peuvent être utiles à la compréhension globale.

1. Les noms importés ne doivent pas entrer en conflit avec les classes définies dans le même fichier
2. Les espaces de noms imbriqués sont interdits
3. Les noms d'espaces de noms dynamiques doivent protéger l'antislash
4. Des constantes indéfinies référencées avec un antislash produisent une erreur fatale
5. Impossible de remplacer des constantes spéciales comme `null`, `true` ou `false`

### Si je n'utilise pas d'espaces de noms, est-ce que je dois m'en soucier ?

Non, les espaces de noms n'affectent pas le code existant, d'une manière ou d'une autre, ni le code qui sera produit et qui n'utilise pas les espaces de noms. Il est possible d'écrire ceci :

Exemple #1 Accès à une classe globale de l'extérieur d'un espace de noms

    <?php
    $a = new \stdClass;
    print $a::class;

C'est une fonctionnalité équivalente à :

Exemple #2 Accéder à des classes globales hors d'un espace de noms

    <?php
    $a = new stdClass;
    print $a::class;

### Comment utiliser une classe globale ou interne depuis un espace de noms ?

Exemple #3 Accès aux classes internes depuis un espace de noms

    <?php
    namespace foo;
    $a = new \stdClass;
    print $a::class . "\n";

    function test(?\ArrayObject $parameter_type_example = null) {}

    $a = \FilesystemIterator::CURRENT_AS_FILEINFO;
    print $a . "\n";

    // extension d'une classe interne ou globale
    class MyException extends \Exception {}
    print MyException::class . "\n";

### Comment utiliser les classes d'espaces de noms, les fonctions ou les constantes dans leur propre espace ?

Exemple #4 Accès aux classes, fonctions et constantes internes dans un espace de noms

    <?php
    namespace foo;

    class MaClasse {}

    // utilisation d'une classe dans l'espace de noms courant, sous forme de type de paramètre
    function test(?MaClasse $parameter_type_example = null) {}

    // une autre manière d'utiliser une classe dans l'espace de noms courant comme type de paramètre
    function test2(?\foo\MaClasse $parameter_type_example = null) {}

    // extension d'une classe dans l'espace de noms courant
    class Extended extends MaClasse {}
    print Extended::class . "\n";

    // accès à une fonction globale
    $a = \strlen("test");
    print $a . "\n";

    // accès à une constante globale
    $b = \INI_ALL;
    print $b . "\n";

### Comment est-ce qu'un nom comme `\mon\nom` ou `\nom` est résolu ?

Les noms qui commencent par `\` sont toujours résolus en ce à quoi ils ressemblent, ce qui fait que `\mon\nom` est en fait `mon\nom`, et `\Exception` est `Exception`.

Exemple #5 Noms d'espaces absolus

    <?php
    namespace foo;
    $a = new \mon\nom(); // instancie la classe "mon\nom"
    echo \strlen('hi'); // appelle la fonction "strlen"
    $a = \INI_ALL; // $a reçoit la valeur de la constante "INI_ALL"

### Comment est-ce qu'un nom tel que `mon\nom` est résolu ?

Les noms qui contiennent un antislash mais ne commencent pas par un antislash, comme `mon\nom` peuvent être résolus de deux manières différentes.

S'il y a eu une commande d'importation qui fait un alias de `mon`, alors l'alias importé est appliqué à la place de `mon`, et l'espace de noms devient `mon\nom`.

Sinon, l'espace de noms courant est ajouté avant le chemin de la classe `mon\nom`.

Exemple #6 Noms qualifiés

    <?php
    namespace foo;
    use blah\blah as foo;

    $a = new mon\nom(); // instancie la classe "foo\mon\nom"
    foo\bar::name(); // appelle la méthode statique "name" dans la classe "blah\blah\bar"
    mon\bar(); // appelle la fonction "foo\mon\bar"
    $a = mon\BAR; // affecte à $a la valeur de la constante "foo\mon\BAR"

### Comment un nom de classe sans qualification, tel que `nom`, est résolu ?

Les noms de classes qui ne contiennent pas d'antislash comme `nom` peuvent être résolus de deux manières différentes.

S'il y a une instruction d'importation qui définit un alias pour `nom`, alors l'alias est appliqué.

Sinon, l'espace de noms courant est utilisé et préfixé à `nom`.

Exemple #7 Classes sans qualification

    <?php
    namespace foo;
    use blah\blah as foo;

    $a = new nom(); // instancie la classe "foo\nom"
    foo::nom(); // appelle la méthode statique "nom" dans la classe "blah\blah"

### Comment une fonction sans qualification ou une constante de nom `nom` est résolue ?

Les fonctions et constantes qui n'ont pas d'antislash dans leur nom comme `nom` sont résolues de deux manières différentes :

D'abord, l'espace de noms courant est préfixé à `nom`.

Ensuite, si la constante ou la fonction `nom` n'existe pas dans l'espace de noms courant, la version globale de la constante ou la fonction `nom` est utilisée.

Exemple #8 Fonctions et constantes sans espace de noms

    <?php
    namespace foo;
    use blah\blah as foo;

    const FOO = 1;

    function mon() {
        print __FUNCTION__ . "\n";
    }
    function foo() {
        print __FUNCTION__ . "\n";
    }
    function sort(&$a)
    {
        \sort($a); // Appel de la fonction globale "sort"
        $a = array_flip($a);
        return $a;
    }

    mon(); // appelle "foo\mon"
    print strlen('hi') . "\n"; // appelle la fonction globale "strlen" car "foo\strlen" n'existe pas
    $arr = array(1,3,2);
    $b = sort($arr); // appelle la fonction "foo\sort"
    var_dump($b);
    foo(); // appelle la fonction "foo\foo" : l'importation n'est pas appliquée

    $a = FOO; // assigne à $a la valeur de la constante "foo\FOO" : l'importation n'est pas appliquée
    print $a;
    $b = INI_ALL; // assigne à $b la valeur de la constante "INI_ALL"
    print $b;

### Les noms importés ne doivent pas entrer en conflit avec les classes définies dans le même fichier

La combinaison de scripts suivante est valide :

file1.php

    <?php
    namespace mes\trucs;
    class MaClasse {}

another.php

    <?php
    namespace another;
    class untruc {}

file2.php

    <?php
    namespace mes\trucs;
    include 'file1.php';
    include 'another.php';

    use another\untruc as MaClasse;
    $a = new MaClasse; // instancie la classe "untruc" de l'espace de noms another

Il n'y a pas de conflit de noms, même si la classe `MaClasse` existe dans l'espace de noms `mes\trucs`, car la définition de `MaClasse` est dans un fichier séparé. Cependant, l'exemple suivant produit une erreur fatale à cause d'un conflit de noms, car `MaClasse` est définie dans le même fichier que l'instruction `use`.

    <?php
    namespace mes\trucs;
    use another\untruc as MaClasse;
    class MaClasse {} // erreur fatale: MaClasse est en conflit avec la commande d'importation
    $a = new MaClasse;

### Les espaces de noms imbriqués sont interdits

PHP ne permet pas d'imbriquer des espaces de noms.

    <?php
    namespace mes\trucs {
        namespace nested {
            class foo {}
        }
    }

Cependant, il est facile de simuler des espaces de noms imbriqués, comme ceci :

    <?php
    namespace mes\trucs\nested {
        class foo {}
    }

### Les noms d'espaces de noms dynamiques doivent protéger l'antislash

Il est très important de réaliser que, comme les antislash sont utilisés comme caractères de protection dans les chaînes, il faut toujours les doubler pour pouvoir les utiliser dans une chaîne. Sinon, il y a un risque d'utilisation inattendue :

Exemple #9 Dangers de l'utilisation des espaces de noms dans une chaîne

    <?php
    $a = "dangereux\nom"; // \n est une nouvelle ligne dans une chaîne!
    $obj = new $a;

    $a = 'pas\vraiment\dangereux'; // aucun problème ici
    $obj = new $a;

Dans une chaîne à guillemets simples, la séquence de protection est beaucoup plus sûre à utiliser, mais il est quand même recommandé de toujours protéger les antislashs dans toutes les chaînes comme bonne pratique.

### Des constantes indéfinies référencées avec un antislash produisent une erreur fatale

Toute constante indéfinie qui est sans qualificatif telle que `FOO` va produire une alerte : PHP supposait que `FOO` était la valeur de la constante. Toute constante, qualifiée partiellement ou totalement, qui contient un antislash, produit une erreur fatale si indéfinie.

Exemple #10 Constantes indéfinies

    <?php
    namespace bar;
    $a = FOO; // produit une alerte : constante indéfinie "FOO", qui prend la valeur de "FOO";
    $a = \FOO; // erreur fatale, constante d'espace de noms indéfinie FOO
    $a = Bar\FOO; // erreur fatale, constante d'espace de noms indéfinie bar\Bar\FOO
    $a = \Bar\FOO; // erreur fatale, constante d'espace de noms indéfinie Bar\FOO

### Impossible de remplacer des constantes spéciales comme `null`, `true` ou `false`

Toute tentative dans un espace de noms de remplacer les constantes natives ou spéciales, engendre une erreur fatale.

Exemple #11 Constantes qui ne peuvent être redéfinies

    <?php
    namespace bar;
    const NULL = 0; // erreur fatale;
    const true = 'stupid'; // encore une erreur fatale;
    // etc.

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open