PHP Namespace
PHP namespaces were introduced in PHP 5.3 to solve the problem of duplicate names. In PHP, two functions or classes cannot have the same name; otherwise, a fatal error occurs.
PHP namespaces can solve the following two types of problems:
- Name conflicts between user-written code and PHP's internal classes/functions/constants or third-party classes/functions/constants.
- Create an alias (or short) name for very long identifier names (usually defined to mitigate the first type of problem), improving the readability of source code.
Defining Namespaces
By default, all constants, classes, and function names are placed in the global space, just as before PHP supported namespaces.
Namespaces are declared using the keyword `namespace`. If a file contains a namespace, it must declare the namespace before all other code.
The syntax is as follows:
<?php // 定义代码在 'MyProject' 命名空间中 namespace MyProject; // ... 代码 ...
You can also define different namespace code in the same file, for example:
<?php
namespace MyProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
namespace AnotherProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
It is not recommended to use this syntax to define multiple namespaces in a single file. It is recommended to use the brace syntax below.
<?php
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace AnotherProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
?>
To combine global non-namespace code with namespace code, you can only use the brace syntax. The global code must be enclosed in a nameless `namespace` statement plus braces, for example:
<?php
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // 全局代码
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>
The only legal code before declaring a namespace is the `declare` statement used to define the source file encoding. All non-PHP code, including whitespace, cannot appear before the 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>” 会致命错误 - 命名空间必须是程序脚本的第一条语句 ?>
Subnamespaces
Much like the relationship between directories and files, PHP namespaces also allow specifying hierarchical namespace names. Therefore, namespace names can be defined in a hierarchical way:
<?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`.
Using Namespaces
Class names in PHP namespaces can be referenced in three ways:
Unqualified names, or class names without a prefix,For example `$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 not contained in any namespace, `foo` will be resolved to `foo`. Warning: If a function or constant in a namespace is not defined, the unqualified function name or constant name will be resolved to the global function name or constant name.
Qualified names, or names with a prefix,For example `$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 not contained in any namespace, `foo` will be resolved to `subnamespace\foo`.
Fully qualified names, or names that include the 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 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
foo::staticmethod(); // 解析为类 Foo\Bar\foo ,方法为 staticmethod
echo FOO; // 解析为常量 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
?>
Note that any global class, function, or constant can be accessed using a fully qualified name, such as `\strlen()`, `\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
The implementation of PHP namespaces is affected by the dynamic features of the language itself. Therefore, to convert the following code into namespaces, you need to access 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
?>
You must use fully qualified names (class names including the namespace prefix). Note that because there is no difference between qualified names and fully qualified names in dynamic class names, function names, or constant names, the leading backslash is unnecessary.
Dynamically accessing 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; // 输出 classname::__construct
$b = 'funcname';
$b(); // 输出函数名
echo constant('constname'), "\n"; // 输出 global
/* 如果使用双引号,使用方法为 "\\namespacename\\classname"*/
$a = '\namespacename\classname';
$obj = new $a; // 输出 namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // 输出 namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // 输出 namespacename\funcname
$b = '\namespacename\funcname';
$b(); // 输出 namespacename\funcname
echo constant('\namespacename\constname'), "\n"; // 输出 namespaced
echo constant('namespacename\constname'), "\n"; // 输出 namespaced
?>
The namespace keyword and the __NAMESPACE__ constant
PHP supports two abstract methods for accessing elements in the current namespace: the `__NAMESPACE__` magic constant and the `namespace` keyword.
The value of the `__NAMESPACE__` constant is a string containing the current namespace name. 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__` example, global code
<?php echo '"', __NAMESPACE__, '"'; // 输出 "" ?>
The constant `__NAMESPACE__` is useful when dynamically creating names, for example:
Using `__NAMESPACE__` to dynamically create names
<?php
namespace MyProject;
function get($classname)
{
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
?>
The `namespace` keyword can be used to explicitly access elements in the current namespace or a subnamespace. It is equivalent to the `self` operator in classes.
The `namespace` operator, code in a namespace
<?php namespace MyProject; use blah\blah as mine; // 引入了 blah\blah 命名空间,并定义了个别名mine mine\mine(); // 调用函数 blah\blah\mine() namespace\blah\mine(); // 调用函数 MyProject\blah\mine() namespace\func(); // 调用函数 MyProject\func() namespace\sub\func(); // 调用函数 MyProject\sub\func() namespace\cname::method(); // 调用 MyProject\cname 类的静态方法 $a = new namespace\sub\cname(); // 实例化 MyProject\sub\cname 类的对象 $b = namespace\CONSTANT; // 将常量 MyProject\CONSTANT 的值赋给 $b ?>
The `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: Aliases/Imports
PHP namespace support has two ways of using aliases or imports: using an alias for class names, or using an alias for namespace names.
In PHP, aliases are implemented with the `use` operator. The following is an example using all three possible import methods:
1. Importing/using aliases with the `use` operator
<?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. Including multiple `use` statements in one line
<?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 at compile time, but dynamic class names, function names, or constant names are not.
3. Imports 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, being deterministic, are not affected by imports.
4. Imports and fully qualified names
<?php use My\Full\Classname as Another, My\Full\NSname; $obj = new Another; // 实例化 My\Full\Classname 类 $obj = new \Another; // 实例化 Another 类 $obj = new Another\thing; // 实例化 My\Full\Classname\thing 类 $obj = new \Another\thing; // 实例化 Another\thing 类 ?>
Using Namespaces: Fallback Global Functions/Constants
In a namespace, when PHP encounters an unqualified class, function, or constant name, it uses different priority strategies to resolve the name. Class names are always resolved to names in the current namespace. Therefore, when accessing internal system class names or class names not contained in a namespace, you must use fully qualified names, for example:
1. Accessing global classes in a 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 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. Fallback global functions/constants in namespaces
<?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 class and function definitions are in the global space, just as before PHP introduced the concept of namespaces. Adding the prefix `\` before a name indicates that the name is a name in the global space, even if the name is located in other namespaces.
Explanation of using global space
<?php
namespace A\B\C;
/* 这个函数是 A\B\C\fopen */
function fopen() {
/* ... */
$f = \fopen(...); // 调用全局的fopen函数
return $f;
}
?>
Namespace Resolution Order
Since the advent of namespaces, the most error-prone thing is when using classes: what is the class's search path?
<?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" 的 "foo" 方法
// 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
?>
Name resolution follows the following rules:
- Calls to functions, classes, and constants with fully qualified names are resolved at compile time. For examplenew \A\BResolves to classA\B。
- All unqualified names and qualified names (non-fully qualified names) are converted at compile time according to the current import rules. For example, if the namespaceA\B\Cis imported asC, then a call toC\D\e()will be converted toA\B\C\D\e()。
- Inside a namespace, all qualified names that have not been converted according to import rules will have the current namespace name prepended to them. For example, in the namespaceA\BcallingC\D\e(), thenC\D\e()will be converted toA\B\C\D\e() 。
- Unqualified class names are converted at compile time according to the current import rules (the full name replaces the short imported name). For example, if the namespaceA\B\Cis imported as C, thennew C()is converted tonew A\B\C() 。
- Inside a namespace (e.g., A\B), function calls to unqualified names are resolved at runtime. For example, for the functionfoo()the call is resolved as follows:
- Look up in the current namespace for a function namedA\B\foo()function
- Try to find and call theGlobalfunction in the global spacefoo()。
- Inside a namespace (e.g.,A\B), calls to unqualified or qualified class names (not fully qualified names) are resolved at runtime. The following is the resolution process for callingnew C()andnew D\E()the resolution process: new C()resolution of:
- Search for theA\B\Cclass in the current namespace.
- Attempt to autoload classA\B\C。
- Prefix the current namespace name to the class name, resulting in:A\B\D\E, then look for that class.
- Attempt to autoload classA\B\D\E。