PHP 8.3.4 Released!

Foire aux questions : ce que vous devez 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. Vous pouvez écrire ceci si vous voulez :

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

<?php
$a
= new \stdClass;
?>

C'est une fonctionnalité équivalente à :

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

<?php
$a
= new stdClass;
?>

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;

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

$a = \DirectoryIterator::CURRENT_AS_FILEINFO;

// extension d'une classe interne ou globale
class MyException extends \Exception {}
?>

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 test(\foo\MaClasse $parameter_type_example = null) {}

// extension d'une classe dans l'espace de noms courant
class Extended extends MaClasse {}

// accès à une fonction globale
$a = \globalfunc();

// accès à une constante globale
$b = \INI_ALL;
?>

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(); // instantie 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 par 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(); // instantie 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(); // instantie 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 nom 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() {}
function
foo() {}
function
sort(&$a)
{
\sort($a); // Appel de la fonction globale "sort"
$a = array_flip($a);
return
$a;
}

mon(); // appelle "foo\mon"
$a = strlen('hi'); // appelle la fonction globale "strlen" car "foo\strlen" n'existe pas
$arr = array(1,3,2);
$b = sort($arr); // appelle la fonction "foo\sort"
$c = 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
$b = INI_ALL; // assigne à $b la valeur de la constante "INI_ALL"
?>

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; // instantie 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 à double guillemets, la séquence de protection est beaucoup plus sécuritaire à utiliser, mais il est quand même recommandé de toujours protéger les antislashs dans une chaîne qui contient un espace de noms.

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 produite une alerte : PHP supposait que FOO était la valeur de la constante. Toute constante, qualifiée partiellement ou totalement, qui contient un antislash, produite 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.
?>

add a note

User Contributed Notes 6 notes

up
15
manolachef at gmail dot com
11 years ago
There is a way to define a namespaced constant that is a special, built-in constant, using define function and setting the third parameter case_insensitive to false:

<?php
namespace foo;
define(__NAMESPACE__ . '\NULL', 10); // defines the constant NULL in the current namespace
var_dump(NULL); // will show 10
var_dump(null); // will show NULL
?>

No need to specify the namespace in your call to define(), like it happens usually
<?php
namespace foo;
define(INI_ALL, 'bar'); // produces notice - Constant INI_ALL already defined. But:

define(__NAMESPACE__ . '\INI_ALL', 'bar'); // defines the constant INI_ALL in the current namespace
var_dump(INI_ALL); // will show string(3)"bar". Nothing unespected so far. But:

define('NULL', 10); // defines the constant NULL in the current namespace...
var_dump(NULL); // will show 10
var_dump(null); // will show NULL
?>

If the parameter case_insensitive is set to true
<?php
namespace foo;
define (__NAMESPACE__ . '\NULL', 10, true); // produces notice - Constant null already defined
?>
up
7
shaun at slickdesign dot com dot au
7 years ago
When creating classes or calling static methods from within namespaces using variables, you need to keep in mind that they require the full namespace in order for the appropriate class to be used; you CANNOT use an alias or short name, even if it is called within the same namespace. Neglecting to take this into account can cause your code to use the wrong class, throw a fatal missing class exception, or throw errors or warnings.

In these cases, you can use the magic constant __NAMESPACE__, or specify the full namespace and class name directly. The function class_exists also requires the full namespace and class name, and can be used to ensure that a fatal error won't be thrown due to missing classes.

<?php

namespace Foo;
class
Bar {
public static function
test() {
return
get_called_class();
}
}

namespace
Foo\Foo;
class
Bar extends \Foo\Bar {
}

var_dump( Bar::test() ); // string(11) "Foo\Foo\Bar"

$bar = 'Foo\Bar';
var_dump( $bar::test() ); // string(7) "Foo\Bar"

$bar = __NAMESPACE__ . '\Bar';
var_dump( $bar::test() ); // string(11) "Foo\Foo\Bar"

$bar = 'Bar';
var_dump( $bar::test() ); // FATAL ERROR: Class 'Bar' not found or Incorrect class \Bar used
up
3
teohad at NOSPAM dot gmail dot com
7 years ago
[Editor's note: that behavior is caused by a bug in PHP 7.0, which has been fixed as of PHP 7.0.7.]

Regarding the entry "Import names cannot conflict with classes defined in the same file".
- I found that since PHP 7.0 this is no longer the case.
In PHP 7.0 you can have a class with a name that matches an imported class (or namespace or both at the same time).

<?php
namespace ns1 {
class
ns1 {
public static function
write() {
echo
"ns1\\ns1::write()\n";
}
}
}

namespace
ns1\ns1 {
class
ns1c {
public static function
write() {
echo
"ns1\\ns1\\ns1c::write()\n";
}
}
}

namespace
ns2 {
use
ns1\ns1 as ns1; // both a class in ns1, and a namespace ns1\ns1

// the next class causes fatal error in php 5.6, not in 7.0
class ns1 {
public static function
write() {
echo
"ns2\\ns1::write()\n";
}
}

ns1::write(); // calls imported ns1\ns1::write()
ns1\ns1c::write(); // calls imported ns1\ns1\ns1c::write()
namespace\ns1::write(); // calls ns2\ns1::write()
}
?>
up
2
theking2 at king dot ma
1 year ago
Just like class names currently namespaces are not case sensitive. So no errors will be shown here:

<?php declare(strict_types=1);
namespace
Foo;
class
Bar {
public function
__construct() {
echo
'Map constructed';
}
}

$foobar = new \foo\bar();
up
6
phpcoder
8 years ago
Regarding "Neither functions nor constants can be imported via the use statement." Actually you can do it in PHP 5.6+:

<?php

// importing a function (PHP 5.6+)
use function My\Full\functionName;

// aliasing a function (PHP 5.6+)
use function My\Full\functionName as func;

// importing a constant (PHP 5.6+)
use const My\Full\CONSTANT;
?>
up
-4
okaresz
10 years ago
To correct manolachef's answer: define() ALWAYS defines constants in the GLOBAL namespace.

As nl-x at bita dot nl states in the note at http://www.php.net/manual/en/function.define.php, the constant "NULL" can be defined with define() case-sensitively, but can only be retrieved with constant(), leaving the meaning of NULL uppercase keyword as the only value of the type null.
To Top