Espace de noms PHP


Qu'est-ce qu'un espace de noms ?

D'une manière générale, un espace de noms est une manière d'encapsuler des choses. Cette abstraction peut être trouvée à de nombreux endroits.

Par exemple, dans le système d'exploitation, les répertoires sont utilisés pour regrouper les fichiers associés. Pour les fichiers du répertoire, il joue le rôle d'un espace de noms.

Par exemple, le fichier foo.txt peut exister dans les répertoires /home/greg et /home/other en même temps, mais deux fichiers foo.txt ne peuvent pas exister dans le même répertoire.

De plus, lors de l'accès au fichier foo.txt en dehors du répertoire /home/greg, nous devons mettre le nom du répertoire et le séparateur de répertoire avant le nom du fichier pour obtenir /home/greg/foo.txt. L'application de ce principe au domaine de la programmation est le concept d'espace de noms.

L'espace de noms PHP (espace de noms) a été ajouté dans PHP 5.3 Si vous avez étudié le C# et Java, alors l'espace de noms n'a rien de nouveau. Cependant, cela a toujours une importance très importante en PHP.

Le rôle des espaces de noms PHP

L'un des objectifs les plus clairs des espaces de noms est de résoudre le problème des noms en double avec deux fonctions ou classes. le même nom apparaît, sinon une erreur fatale sera générée. Dans ce cas, le problème peut être résolu à condition d'éviter la duplication de nom. La méthode la plus courante consiste à se mettre d'accord sur un préfixe.

L'espace de noms PHP peut résoudre les deux types de problèmes suivants :

1. Code écrit par l'utilisateur et classes/fonctions/constantes internes PHP ou classes/fonctions tierces. / Conflit de noms entre constantes.

2. Créez un nom d'alias (ou court) pour un nom d'identifiant très long (généralement défini pour atténuer le premier type de problème) afin d'améliorer la lisibilité du code source.

Comment PHP définit les espaces de noms

Par défaut, toutes les constantes, classes et noms de fonctions sont placés dans l'espace global, tout comme la prise en charge des espaces de noms PHP est le même qu'avant.

Un espace de noms est déclaré à l'aide du mot-clé namespace. Si un fichier contient un espace de noms, il doit déclarer l'espace de noms avant tout autre code. Le format de syntaxe est le suivant :

<?php  
// 定义代码在 'MyProject' 命名空间中  
namespace MyProject;  
// ... 代码 ...

Vous pouvez également définir différents codes d'espace de noms dans le même fichier, tels que :

<?php  
namespace MyProject1;  
// MyProject1 命名空间中的PHP代码  
namespace MyProject2;  
// MyProject2 命名空间中的PHP代码    
// 另一种语法
namespace MyProject3 {  
 // MyProject3 命名空间中的PHP代码    
}  
?>

Le seul code légal avant de déclarer un espace de noms est destiné à définir le fichier source. Encodage de l'instruction de déclaration. Tout code non PHP, y compris les espaces, ne doit pas apparaître avant une déclaration d'espace de noms.

<?php
declare(encoding='UTF-8'); //定义多个命名空间和不包含在命名空间中的代码
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }
}
namespace { // 全局代码
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>

Le code suivant provoquera une erreur de syntaxe :

<html>
<?php
namespace MyProject; // 命名空间前出现了“<html>” 会致命错误 - 命名空间必须是程序脚本的第一条语句
?>

Sous-espace de noms

est très similaire aux répertoires et aux fichiers , les espaces de noms PHP vous permettent également de spécifier des noms d'espaces de noms hiérarchiques. Par conséquent, les noms d'espaces de noms peuvent être définis de manière hiérarchique :

<?php
namespace MyProject\Sub\Level;  //声明分层次的单个命名空间
const CONNECT_OK = 1;
class Connection { /* ... */ }
function Connect() { /* ... */  }
?>

L'exemple ci-dessus crée la constante MyProjectSubLevelCONNECT_OK, la classe MyProjectSubLevelConnection et la fonction MyProjectSubLevelConnect.

Utilisation de l'espace de noms

Les noms de classe dans l'espace de noms PHP peuvent être référencés de trois manières :

1. Noms non qualifiés ou noms de classe sans préfixes, tels que $a=new foo( ou foo:: staticmethod()); ;. Si l'espace de noms actuel est currentnamespace, foo sera résolu en currentnamespacefoo. Si le code utilisant foo est global et ne contient de code dans aucun espace de noms, foo sera résolu comme foo. Avertissement : Si une fonction ou une constante dans l'espace de noms n'est pas définie, la fonction ou le nom de constante non qualifié est résolu en une fonction globale ou un nom de constante.

2. Nom qualifié ou nom contenant un préfixe, tel que $a = new subnamespacefoo(); ou subnamespacefoo::staticmethod();. Si l'espace de noms actuel est currentnamespace, foo sera résolu en currentnamespacesubnamespacefoo. Si le code utilisant foo est global, code non contenu dans aucun espace de noms, foo sera résolu en subnamespacefoo.

3. Nom complet ou nom qui inclut un opérateur de préfixe global, par exemple, $a = new currentnamespacefoo();. Dans ce cas, foo est toujours résolu en nom littéral currentnamespacefoo dans le code.

Ce qui suit est un exemple d'utilisation de ces trois méthodes :

code de fichier file1.php

<?php
namespace Foo\Bar\subnamespace; 
const FOO = 1;
function foo() {}
class foo
{
    static function staticmethod() {}
}
?>

code de fichier file2.php

<?php
namespace Foo\Bar;
include 'file1.php';
const FOO = 2;
function foo() {}
class foo
{
    static function staticmethod() {}
}
/* 非限定名称 */
foo(); // 解析为 Foo\Bar\foo resolves to function Foo\Bar\foo
foo::staticmethod(); // 解析为类 Foo\Bar\foo的静态方法staticmethod。resolves to class Foo\Bar\foo, method staticmethod
echo FOO; // resolves to constant Foo\Bar\FOO
/* 限定名称 */
subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo,
                                  // 以及类的方法 staticmethod
echo subnamespace\FOO; // 解析为常量 Foo\Bar\subnamespace\FOO
                                  
/* 完全限定名称 */
\Foo\Bar\foo(); // 解析为函数 Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
echo \Foo\Bar\FOO; // 解析为常量 Foo\Bar\FOO
?>

Attention à accéder à toutes les classes, fonctions ou constantes globales peut utiliser des noms complets, tels que strlen() ou Exception ou INI_ALL.

Accédez aux classes, fonctions et constantes globales à l'intérieur d'un espace de noms :

<?php
namespace Foo;
function strlen() {}
const INI_ALL = 3;
class Exception {}
$a = \strlen('hi'); // 调用全局函数strlen
$b = \INI_ALL; // 访问全局常量 INI_ALL
$c = new \Exception('error'); // 实例化全局类 Exception
?>

Espaces de noms et fonctionnalités de langage dynamique

PHP L'implémentation d'un espace de noms est affecté par la nature dynamique du langage lui-même. Donc, si vous souhaitez convertir le code ci-dessous en espace de noms, accédez aux éléments de manière dynamique.

code de fichier exemple1.php :

<?php
class classname
{
    function __construct()
    {
        echo __METHOD__,"\n";
    }
}
function funcname()
{
    echo __FUNCTION__,"\n";
}
const constname = "global";
$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
?>

Doit utiliser un nom complet (nom de classe incluant le préfixe d'espace de noms). Notez que la barre oblique inverse n'est pas nécessaire car il n'y a aucune différence entre les noms qualifiés et complets dans les noms de classes dynamiques, les noms de fonctions ou les noms de constantes.

Accès dynamique aux éléments de l'espace de noms

<?php
namespace namespacename;
class classname
{
    function __construct()
    {
        echo __METHOD__,"\n";
    }
}
function funcname()
{
    echo __FUNCTION__,"\n";
}
const constname = "namespaced";
include 'example1.php';
$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
/* note that if using double quotes, "\namespacename\classname" must be used */
$a = '\namespacename\classname';
$obj = new $a; // prints namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // also prints namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // prints namespacename\funcname
$b = '\namespacename\funcname';
$b(); // also prints namespacename\funcname
echo constant('\namespacename\constname'), "\n"; // prints namespaced
echo constant('namespacename\constname'), "\n"; // also prints namespaced
?>

mot-clé de l'espace de noms et constante __NAMESPACE__

PHP prend en charge deux abstractions Méthodes d'accès aux éléments à l'intérieur l'espace de noms actuel, la constante magique __NAMESPACE__ et le mot-clé de l'espace de noms.

La valeur de la constante __NAMESPACE__ est une chaîne contenant le nom de l'espace de noms actuel. Dans le code global, non inclus dans aucun espace de noms, il contient une chaîne vide.

Exemple __NAMESPACE__, code dans l'espace de noms

<?php
namespace MyProject;
echo '"', __NAMESPACE__, '"'; // 输出 "MyProject"
?>
__NAMESPACE__ 示例,全局代码
<?php
echo '"', __NAMESPACE__, '"'; // 输出 ""
?>

La constante __NAMESPACE__ est utile lors de la création dynamique de noms, par exemple :

Créez des noms dynamiquement en utilisant __NAMESPACE__

<?php
namespace MyProject;
function get($classname)
{
    $a = __NAMESPACE__ . '\' . $classname;
    return new $a;
}
?>

Le mot clé espace de noms peut être utilisé pour accéder explicitement aux éléments de l'espace de noms ou des sous-espaces de noms actuels. C'est l'équivalent de l'auto-opérateur en classe.

opérateur d'espace de noms, code dans l'espace de noms

<?php
namespace MyProject;
use blah\blah as mine; // see "Using namespaces: importing/aliasing"
blah\mine(); // calls function blah\blah\mine()
namespace\blah\mine(); // calls function MyProject\blah\mine()
namespace\func(); // calls function MyProject\func()
namespace\sub\func(); // calls function MyProject\sub\func()
namespace\cname::method(); // calls static method "method" of class MyProject\cname
$a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname
$b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b
?>

opérateur d'espace de noms, code global

<?php
namespace\func(); // calls function func()
namespace\sub\func(); // calls function sub\func()
namespace\cname::method(); // calls static method "method" of class cname
$a = new namespace\sub\cname(); // instantiates object of class sub\cname
$b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b
?>

Utilisation des espaces de noms : Alias/Imports

La prise en charge des espaces de noms PHP propose deux manières d'utiliser des alias ou des importations : en utilisant des alias pour les noms de classe ou en utilisant des noms d'espace de noms pseudonymes. Notez que PHP ne prend pas en charge l'importation de fonctions ou de constantes.

En PHP, les alias sont implémentés via l'opérateur use. Voici un exemple d'utilisation des trois méthodes d'importation possibles :

1. Utilisez l'opérateur use pour importer/utiliser des alias

.
<?php
namespace foo;
use My\Full\Classname as Another;
// 下面的例子与 use My\Full\NSname as NSname 相同
use My\Full\NSname;
// 导入一个全局类
use \ArrayObject;
$obj = new namespace\Another; // 实例化 foo\Another 对象
$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // 实例化 ArrayObject 对象
// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
?>

2. Une ligne contient plusieurs instructions d'utilisation

<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
?>

L'opération d'importation est exécutée lors de la compilation, mais le nom de la classe dynamique, le nom de la fonction ou le nom de la constante ne l'est pas.

3. Import et noms dynamiques

<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // 实例化一个 My\Full\Classname 对象
$a = 'Another';
$obj = new $a;      // 实际化一个 Another 对象
?>

De plus, l'opération d'import n'affecte que les noms non qualifiés et les noms qualifiés. Les noms pleinement qualifiés ne sont pas affectés par les importations car ils sont déterministes.

4. Imports et noms complets

<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // instantiates object of class My\Full\Classname
$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class Another\thing
?>

Utiliser l'espace de noms : fonctions/constantes globales de secours

dans un espace nommé , lorsque PHP rencontre un nom de classe, de fonction ou de constante non qualifié, il utilise une stratégie de priorité différente pour résoudre le nom. Les noms de classe sont toujours résolus en noms dans l'espace de noms actuel. Par conséquent, lorsque vous accédez à des noms de classe à l'intérieur du système ou non inclus dans l'espace de noms, vous devez utiliser des noms complets, par exemple :

1. Accédez aux classes globales dans l'espace de noms

<?php
namespace A\B\C;
class Exception extends \Exception {}
$a = new Exception('hi'); // $a 是类 A\B\C\Exception 的一个对象
$b = new \Exception('hi'); // $b 是类 Exception 的一个对象
$c = new ArrayObject; // 致命错误, 找不到 A\B\C\ArrayObject 类
?>

Pour les fonctions et Pour les constantes, si la fonction ou la constante n'existe pas dans l'espace de noms actuel, PHP reviendra à utiliser la fonction ou la constante dans l'espace global.

2. Sauvegardez les fonctions/constantes globales dans l'espace de noms

<?php
namespace A\B\C;
const E_ERROR = 45;
function strlen($str)
{
    return \strlen($str) - 1;
}
echo E_ERROR, "\n"; // 输出 "45"
echo INI_ALL, "\n"; // 输出 "7" - 使用全局常量 INI_ALL
echo strlen('hi'), "\n"; // 输出 "1"
if (is_array('hi')) { // 输出 "is not array"
    echo "is array\n";
} else {
    echo "is not array\n";
}
?>

Espace global

Si aucun espace de noms n'est défini, tout les classes et les fonctions sont définies dans l'espace global, tout comme avant que PHP n'introduise le concept d'espace de noms. Le préfixe d'un nom indique que le nom se trouve dans l'espace global, même s'il se trouve dans un autre espace de noms.

Utilisation des instructions spatiales globales

<?php
namespace A\B\C;
/* 这个函数是 A\B\C\fopen */
function fopen() { 
     /* ... */
     $f = \fopen(...); // 调用全局的fopen函数
     return $f;
} 
?>

L'ordre des espaces de noms

Depuis l'introduction des espaces de noms, les plus sujets aux erreurs Lorsqu’il est temps d’utiliser une classe, il est temps de déterminer à quoi ressemble le chemin de recherche de cette classe.

<?php
namespace A;
use B\D, C\E as F;
// 函数调用
foo();      // 首先尝试调用定义在命名空间"A"中的函数foo()
            // 再尝试调用全局函数 "foo"
\foo();     // 调用全局空间函数 "foo" 
my\foo();   // 调用定义在命名空间"A\my"中函数 "foo" 
F();        // 首先尝试调用定义在命名空间"A"中的函数 "F" 
            // 再尝试调用全局函数 "F"
// 类引用
new B();    // 创建命名空间 "A" 中定义的类 "B" 的一个对象
            // 如果未找到,则尝试自动装载类 "A\B"
new D();    // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
            // 如果未找到,则尝试自动装载类 "B\D"
new F();    // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象
            // 如果未找到,则尝试自动装载类 "C\E"
new \B();   // 创建定义在全局空间中的类 "B" 的一个对象
            // 如果未发现,则尝试自动装载类 "B"
new \D();   // 创建定义在全局空间中的类 "D" 的一个对象
            // 如果未发现,则尝试自动装载类 "D"
new \F();   // 创建定义在全局空间中的类 "F" 的一个对象
            // 如果未发现,则尝试自动装载类 "F"
// 调用另一个命名空间中的静态方法或命名空间函数
B\foo();    // 调用命名空间 "A\B" 中函数 "foo"
B::foo();   // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
            // 如果未找到类 "A\B" ,则尝试自动装载类 "A\B"
D::foo();   // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法
            // 如果类 "B\D" 未找到,则尝试自动装载类 "B\D"
\B\foo();   // 调用命名空间 "B" 中的函数 "foo" 
\B::foo();  // 调用全局空间中的类 "B" 的 "foo" 方法
            // 如果类 "B" 未找到,则尝试自动装载类 "B"
// 当前命名空间中的静态方法或函数
A\B::foo();   // 调用命名空间 "A\A" 中定义的类 "B" 的 "foo" 方法
              // 如果类 "A\A\B" 未找到,则尝试自动装载类 "A\A\B"
\A\B::foo();  // 调用命名空间 "A\B" 中定义的类 "B" 的 "foo" 方法
              // 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
?>

La résolution de noms suit les règles suivantes :

1. Les appels aux fonctions, classes et constantes avec des noms complets sont résolus à la compilation temps. Par exemple, le nouveau AB se résout en classe AB.

2. Tous les noms non qualifiés et les noms qualifiés (noms non pleinement qualifiés) sont convertis au moment de la compilation selon les règles d'importation en vigueur. Par exemple, si l'espace de noms ABC est importé en tant que C, alors les appels à CDe() seront convertis en ABCDe().

3. Au sein de l'espace de noms, tous les noms qualifiés qui ne sont pas convertis selon les règles d'importation seront précédés du nom de l'espace de noms actuel. Par exemple, si CDe() est appelé dans l'espace de noms AB, CDe() sera converti en ABCDe().

4. Les noms de classe non qualifiés sont convertis au moment de la compilation selon les règles d'importation actuelles (les noms complets sont utilisés à la place des noms d'importation courts). Par exemple, si l'espace de noms ABC est importé en tant que C, alors new C() est converti en new ABC() .

5. Dans un espace de noms (par exemple AB), les appels de fonction vers des noms non qualifiés sont résolus au moment de l'exécution. Par exemple, un appel à la fonction foo() est analysé comme suit :

a. Recherchez une fonction nommée ABfoo() dans l'espace de noms actuel

b Essayez de trouver et d'appeler la fonction globale foo. () dans l'espace.

6. Les appels à des noms non qualifiés ou à des classes de noms qualifiés (noms non pleinement qualifiés) à l'intérieur d'un espace de noms (par exemple AB) sont résolus au moment de l'exécution. Voici le processus d'analyse d'appel de new C() et new DE() : Analyse de new C() : Analyse de new DE() : Afin de faire référence à la classe globale dans l'espace de noms global, le nom complet new C() doit être utilisé.

a. Ajoutez le nom de l'espace de noms actuel devant le nom de la classe pour devenir : ABDE, puis recherchez la classe.

b. Essayez de charger automatiquement la classe ABDE.

c. Recherchez la classe ABC dans l'espace de noms actuel.

d. Essayez de charger automatiquement la classe ABC.