PHP namespace


What is a namespace?

In a broad sense, a namespace is a way of encapsulating things. This abstract concept can be found in many places.

For example, in the operating system, directories are used to group related files. For the files in the directory, it plays the role of a namespace.

For example, the file foo.txt can exist in the directories /home/greg and /home/other at the same time, but two foo.txt files cannot exist in the same directory.

In addition, when accessing the foo.txt file outside the directory /home/greg, we must put the directory name and directory separator before the file name to get /home/greg/foo.txt. The application of this principle to the field of programming is the concept of namespace.

PHP namespace (namespace) was added in PHP 5.3. If you have studied C# and Java, then namespace is nothing new. However, it still has a very important significance in PHP.

The role of PHP namespaces

One of the clearest purposes of namespaces is to solve the problem of duplicate names. PHP does not allow two functions or Classes with the same name appear, otherwise a fatal error will be generated. In this case, it can be solved as long as you avoid naming duplication. The most common way is to agree on a prefix.

PHP namespace can solve the following two types of problems:

1. User-written code and PHP internal classes/functions/constants or third-party classes/functions/ Name conflict between constants.

2. Create an alias (or short) name for a very long identifier name (usually defined to alleviate the first type of problem) to improve the readability of the source code.

How PHP defines namespace

By default, all constants, classes and function names are placed in the global space, just like PHP Namespace support is the same as before.

The namespace is declared through the keyword namespace. If a file contains a namespace, it must declare the namespace before all other code. The syntax format is as follows;

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

You can also define different namespace codes in the same file, such as:

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

The only legal code before declaring a namespace is the one used to define the source file Encoding declare statement. All non-PHP code, including whitespace, must not appear before a namespace declaration.

<?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();
}
?>

The following code will cause a syntax error:

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

Subnamespace

is very similar to directories and files , PHP namespaces also allow you to specify hierarchical namespace names. Therefore, namespace names can be defined in a hierarchical manner:

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

The above example creates the constant MyProject\Sub\Level\CONNECT_OK, the class MyProject\Sub\Level\Connection and the function MyProject\Sub\Level \Connect.

Namespace usage

Class names in the PHP namespace can be referenced in three ways:

1. Unqualified names, or class names that do not include a prefix, such as $a=new foo(); or foo:: staticmethod();. If the current namespace is currentnamespace, foo will be resolved to currentnamespace\foo. If the code using foo is global and does not contain code in any namespace, foo will be resolved as foo. Warning: If a function or constant in the namespace is undefined, the unqualified function or constant name is resolved to a global function or constant name.

2. Qualified name, or name containing prefix, such as $a = new subnamespace\foo(); or subnamespace\foo::staticmethod();. If the current namespace is currentnamespace, foo will be resolved to currentnamespace\subnamespace\foo. If the code using foo is global and does not contain code in any namespace, foo will be resolved to subnamespace\foo.

3. Fully qualified name, or a name that includes a global prefix operator, for example, $a = new \currentnamespace\foo(); or \currentnamespace\foo::staticmethod();. In this case, foo is always resolved to the literal name currentnamespace\foo in the code.

The following is an example of using these three methods:

file1.php file code

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

file2.php file code

<?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
?>

Be careful to access any Global classes, functions, or constants can use fully qualified names, such as \strlen() or \Exception or \INI_ALL.

Accessing global classes, functions and constants inside a namespace:

<?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
?>

Namespaces and dynamic language features

##PHP The implementation of namespaces is affected by the dynamic nature of the language itself. So if you want to convert the code below into a namespace, access the elements dynamically.

example1.php file code:

<?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
?>

Must use a fully qualified name (class name including namespace prefix). Note that the leading backslash is unnecessary because there is no difference between qualified and fully qualified names in dynamic class names, function names, or constant names.

Dynamic access to namespace elements

<?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
?>

namespace keyword and __NAMESPACE__ constant

PHP supports two abstractions Methods for accessing elements within the current namespace, the __NAMESPACE__ magic constant and the namespace keyword.

The value of the constant __NAMESPACE__ is a string containing the name of the current namespace. In global code, not included in any namespace, it contains an empty string.

__NAMESPACE__ Example, code in a namespace

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

The constant __NAMESPACE__ is useful when creating names dynamically, for example:

Create names dynamically using __NAMESPACE__

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

The keyword namespace can be used to explicitly access elements in the current namespace or sub-namespaces. It is equivalent to the self operator in classes.

namespace operator, code in the namespace

<?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
?>

namespace operator, global code

<?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
?>

Using namespaces: alias/import

PHP namespace supports two ways of using aliases or imports: using aliases for class names, or Namespace names use aliases. Note that PHP does not support imported functions or constants.

In PHP, aliases are implemented through the operator use. The following is an example of using all three possible import methods:

1. Use the use operator to import/use aliases

<?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. One line contains multiple use statements

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

The import operation is executed during compilation, but the dynamic class name, function name or constant name is not.

3. Import and dynamic names

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

In addition, the import operation only affects unqualified names and qualified names. Fully qualified names are not affected by imports because they are deterministic.

4. Imports and fully qualified names

<?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
?>

Use namespace: fallback global functions/constants

In a named space, when PHP encounters an unqualified class, function, or constant name, it uses a different precedence strategy to resolve the name. Class names always resolve to names in the current namespace. Therefore, when accessing class names inside the system or not included in the namespace, you must use fully qualified names, for example:

1. Access global classes in the namespace

<?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 类
?>

For functions and For constants, if the function or constant does not exist in the current namespace, PHP will fall back to using the function or constant in the global space.

2. Backup global functions/constants in the namespace

<?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";
}
?>

Global space

If no namespace is defined , all classes and functions are defined in the global space, just like before PHP introduced the namespace concept. Prefixing a name with \ indicates that the name is in the global space, even if the name is in another namespace.

Using global space instructions

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

The order of namespaces

Since the namespace was created, the most error-prone When it's time to use a class, it's time to figure out what the search path for that class looks like.

<?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"
?>

Name resolution follows the following rules:

1. Calls to functions, classes, and constants with fully qualified names are resolved at compile time. For example new \A\B resolves to class A\B.

2. All unqualified names and qualified names (non-fully qualified names) are converted at compile time according to the current import rules. For example, if namespace A\B\C is imported as C, then calls to C\D\e() will be translated to A\B\C\D\e().

3. Within the namespace, all qualified names that are not converted according to import rules will have the current namespace name in front of them. For example, if C\D\e() is called within namespace A\B, C\D\e() will be converted to A\B\C\D\e().

4. Unqualified class names are converted at compile time according to the current import rules (full names are used instead of short import names). For example, if namespace A\B\C is imported as C, then new C() is converted to new A\B\C() .

5. Within a namespace (such as A\B), function calls to unqualified names are resolved at runtime. For example, the call to function foo() is parsed like this:

a. Find the function named A\B\foo() in the current namespace

b. Try to find and call Function foo() in global space.

6. Calls to unqualified names or qualified name classes (non-fully qualified names) within a namespace (such as A\B) are resolved at runtime. The following is the parsing process of calling new C() and new D\E(): Parsing of new C(): Parsing of new D\E(): In order to refer to the global class in the global namespace, the fully qualified name new must be used \C().

a. Add the current namespace name in front of the class name to become: A\B\D\E, and then search for the class.

b. Try to automatically load class A\B\D\E.

c. Search for classes A\B\C in the current namespace.

d. Try to automatically load class A\B\C.