PHP Namespace (namespace)

What is a namespace? B roadly speaking, namespaces are a way to encapsulate things.

PhP namespaces are added to PHP 5.3, and if you've studied C and Java, namespaces are nothing new. However, in PHP there is still a considerable significance.

PhP namespaces can solve two types of problems:

  1. The user writes code that conflicts with the name of the class/function/constant or third-party class/function/constant within PHP.

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

PhP namespaces provide a way to combine related classes, functions, and constants. N ext, let's take a look at the PHP namespace!

Define the namespace

By default, all constants, classes, and function names are placed in global space, just as PHP supported namespaces.

The namespace is declared by the keyword namespace. I f 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代码    
}  
?>

It is not recommended to use this syntax to define multiple namespaces in a single file. It is recommended to use the syntax in braces below.

<?php
namespace MyProject {
    const CONNECT_OK = 1;
    class Connection { /* ... */ }
    function connect() { /* ... */  }
}

namespace AnotherProject {
    const CONNECT_OK = 1;
    class Connection { /* ... */ }
    function connect() { /* ... */  }
}
?>

Combining code in a global non-namespace with code in a namespace can only use syntax in braces. The global code must be enclosed with a namespace statement without a name, such as:

<?php
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }
}

namespace { // 全局代码
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>

The only legitimate code before declaring the namespace is the declare statement that defines how the source file is encoded. All non-PHP code, including blank characters, cannot appear before the declaration of the namespace.

<?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 have syntax errors:

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

Sub-namespace

Much like directories and files, PHP namespaces also allow you to specify the names of hierarchical namespaces. Therefore, namespace names can be defined hierarchically:

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

The above example creates the constant MyProject, Sub, Level, CONNECT_OK, Class MyProject, Sub, Connect, and the function MyProject, Sub, Level, Connect.


Namespaces are used

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

  1. An unqualified name, or a class name that does not contain a prefix, $a the new foo(); o r foo:: staticmethod(); I f the current namespace is currentnamespace, foo will be resolved to currentnamespace. I f the code that uses foo is global and does not contain code in any namespace, foo is parsed to foo. Warning: If a function or constant in the namespace is not defined, the unqualified function name or constant name is resolved to a global function name or constant name.

  2. Qualifying a name, or a name that contains a prefix, $a , new subnamespace, foo (); o r subnamespace:foo:: staticmethod(); I f the current namespace is currentnamespace, the foo is resolved to currentnamespace.subnamespace\foo. If the code that uses foo is global and does not contain code in any namespace, foo is parsed to subamespace.foo.

  3. A fully qualified name, or a name that contains a global prefix operator, for example, $a . o r s currentnamespace/foo:: staticmethod(); In this case, foo is always parsed to the literal name in the code.

Here's an example of how to use these three ways:

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

Note That access to any global class, function, or constant can be made using a fully qualified name, such as sstrlen() or INI_ALL.

Access global classes, functions, and constants inside the 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
?>

Namespace and dynamic language features

The implementation of PHP namespace is influenced by the dynamic characteristics of its language itself. Therefore, if you want to convert the following code into a namespace, dynamically access the element.

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 a fully qualified name, including the class name of the namespace prefix. Note because there is no difference between a qualified name and a fully qualified name in a dynamic class name, function name, or constant name, its leading backslash is unnecessary.

Dynamic access to the elements of the namespace

<?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 keywords __NAMESPACE__ constants

PHP supports two abstract ways to access elements inside the current namespace, __NAMESPACE__ magic constants and namespace keywords.

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

__NAMESPACE__ example, the code in the namespace

<?php
namespace MyProject;

echo '"', __NAMESPACE__, '"'; // 输出 "MyProject"
?>

__NAMESPACE__ example, global code

<?php

echo '"', __NAMESPACE__, '"'; // 输出 ""
?>

Constant __NAMESPACE__ useful when dynamically creating names, such as:

Use __NAMESPACE__ to create names dynamically

<?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-namespace. It is equivalent to the self operator in the class.

The amespace operator, the 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
?>

Use namespace: alias/import

PhP namespaces support two ways to use alias or import: use an alias for a class name, or use an alias for a namespace name. Note THAT does not support importing functions or constants.

In PHP, the alias is implemented through the operator use. Here's an example of using all three possible ways to import:

1, using the use operator to import/use 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, a line contains more than one use statement

<?php
use My\Full\Classname as Another, My\Full\NSname;

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

Import operations are performed in compilations, but dynamic class names, function names, or constant names are not.

3, import and dynamic name

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 实例化一个 My\Full\Classname 对象
$a = 'Another';
$obj = new $a;      // 实际化一个 Another 对象
?>

In addition, import operations affect only unqualified names and qualified names. A fully qualified name is not affected by the import because it is determined.

4, import and fully qualify the name

<?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 namespaces: Back up global functions/constants

In a namespace, when PHP encounters an unqualified class, function, or constant name, it uses a different priority policy to resolve the name. T he class name is always resolved to the name in the current namespace. Therefore, you must use a fully qualified name when accessing a class name inside the system or that is not included in the namespace, such as:

1, access the global class 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 constants, if the function or constant does not exist in the current namespace, PHP retreats to using a function or constant in the global space.

2, the global function/constant 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 as PHP did before it introduced the namespace concept. A prefix to the name indicates that the name is a name in the global space, even if the name is in another namespace.

Use the global space description

<?php
namespace A\B\C;

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

The order of the namespaces

Since having a namespace, the most error-prone thing to do is what it looks like to look for a path when you use a class.

<?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 fully qualified functions, classes, and constants are resolved at compile time. For example, the new .A.B. resolves to Class A.B.

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

  3. Inside the namespace, all qualified names that are not converted according to the import rules are preceded by the current namespace name. For example, if you call C\D\e() inside the namespace A\B, the C\D\e() will be converted to A\B\C\D\e().

  4. Unqualified class names are converted at compile time based on current import rules (replace short import names with full names). For example, if the namespace A-B-C is imported as C, new C() is converted to new A-B-C().

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

    1. Look for a function named A.B.foo() in the current namespace

    2. Try to find and call the function foo() in the global space.

  6. Calls to unqualified names or qualified name classes (not fully qualified names) within namespaces, such as A-B, are resolved at runtime. Here's how to call new C() and new D-E():
    Analysis of new C():

    1. Look for class A.B.C. in the current namespace.
    2. Try loading class A.B.C. automatically.
    Analysis of the new D-E():
    1. Before the class name, add the current namespace name to: A.B.D.E., and then look for the class.
    2. Try loading class A'B'D'E automatically.
    In order to reference a global class in the global namespace, you must use the fully qualified name new .C().