PHP 命名空间

| 选择喜欢的代码风格  

如前所述,PHP 社区已经有许多开发者开发了大量的代码。这意味着一个类库的 PHP 代码可能使用了另外一个类库中相同的类名。如果他们使用同一个命名空间,那将会产生冲突导致异常。

命名空间 解决了这个问题。如 PHP 手册里所描述,命名空间好比操作系统中的目录,两个同名的文件可以共存在不同的目录下。同理两个同名的 PHP 类可以在不同的 PHP 命名空间下共存,就这么简单。

因此把你的代码放在你的命名空间下就非常重要,避免其他开发者担心与第三方类库冲突。

PSR-4 提供了一种命名空间的推荐使用方式,它提供一个标准的文件、类和命名空间的使用惯例,进而让代码做到随插即用。

2014 年 10 月,PHP-FIG 废弃了上一个自动加载标准: PSR-0,而采用新的自动加载标准 PSR-4。但 PSR-4 要求 PHP 5.3 以上的版本,而许多项目都还是使用 PHP 5.2,所以目前两者都能使用。

如果你在新应用或扩展包中使用自动加载标准,应优先考虑使用 PSR-4

命名空间


通过关键字namespace声明。可以在同一个文件中定义不同的命名空间代码,全局的非命名空间代码与命名空间中的代码通过大括号的形式可以组合在一起

<?php
# 命名空间TestA
namespace TestA{
    class TestA{}
    function test(){}
}

# 命名空间TestB
namespace TestB{
    class TestB{}
    function test(){}
}

# 全局的非命名空间
namespace{
    class TestC{}
    function test(){}
}

子命名空间


与目录和文件的关系很像,PHP命名空间也允许指定层次的命名空间的名称

<?php
namespace a\b\Test; 

?>

命名空间的引入


通过关键字use引入,通过as定义别名

引入命名空间三种情况

  • 非限定名称,或不包含前缀的类名称。在命名空间为 a 下,使用 $a = new foo() ,代表引用的是 a\foo 。在命名空间为全局的情况下,使用该方法则引用的是 foo
  • 限定名称,或包含前缀的名称。在命名空间为 a 下,使用 $a = new b\foo() ;代码引入的是 a\b\foo 。 在命名为全局的情况下,使用该方法引入的是 b\foo
  • 完全限定名称,或包含了全局前缀操作符的名称。在命名空间为 a 下,$a = new \c\b\foo() ;这种情况下,总是引入为 c\b\foor 文件

file1.php 文件代码

<?php
namespace Foo\Bar\subnamespace; 

const FOO = 1;
function foo() {}
class foo
{
    static function staticmethod() {}
}
?>

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

上述三种方式其实就是文件路径中绝对路径和相对路径。

注意:访问任意全局类、函数或变量,都可以使用完全限定名称,例如 \strlen() 或者 \Exception

<?php
namespace foo;

use \A\B\TestA;		#导入命名空间
use \A\B\TestB as TB;	#导入命名空间,并别名为TB

?>

namespace__NAMESPACE__魔术常量

namespace用于定义命名空间,__NAMESPACE__是包含当前命名空间的字符串,在全局的情况下,它是一个空字符串''

NAMESPACE 示例, 在命名空间中的代码

<?php
namespace MyProject;

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

NAMESPACE 示例,全局代码

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

常量 NAMESPACE 在动态创建名称时很有用,例如:使用 __NAMESPACE__ 动态创建名称

<?php
namespace MyProject;

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

学习总结


1.只有三种类型受命名空间的影响:类、函数、常量
2.使用namespace来声明(类似文件目录)
3.除非使用declare,否则namespace前不能有任何PHP和HTML代码(包括空白符)
4.同一命名空间可以定义在多个文件中,但分割开的命名空间中,上述三个类型也不能重名

坑:


在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。

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

以下代码会出现语法错误

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

PHP 命名空间扩展阅读:





发表评论