[ PHP 学习笔记 ] 命名空间

【摘录】:“命名空间在PHP5.3.0中引入,是一个很重要的工具,其作用是按照一种虚拟的层次结构组织PHP代码,这种层次结构类似操作系统中文件系统的目录结构,现代的PHP组件和框架都放在各自全局唯一的厂商命名空间中,以免与其他厂商使用常见类名冲突”-- O'REILLY《 Modern PHP 》

【意义】:试想下在团队合作开发中如果项目结构复杂参与人员繁多的情况下,各自的包与扩展很可能会发生冲突,命名空间很好的解决了这一问题,并且通过Composer能够让各种第三方组件与项目良好的结合并且无需考虑兼容与冲突的问题

【举例】【一般情况】:

# @ 若声明类时类名重复,则会产生一个致命错误
class test{  }
class test{  }
# @ 类名重复导致一个致命错误
( ! ) Fatal error: Cannot redeclare class test in D:\WAMP\www\JustTest\index.php on line 6Call Stack#TimeMemoryFunctionLocation10.0004233528{main}( )...\index.php:0

【举例】【命名空间】:

# @ 使用命名空间
namespace TestSpace_01;
class test{  }
namespace TestSpace_02;
class test{ }

【摘录】【总结】:PHP命名空间与操作系统的物理文件不同,这是一个虚拟的概念,没必要和文件系统中的目录结构完全对应。虽然如此,但是大多数PHP组件为了兼容广泛使用的PSR-4自动加载标准,会把子命名空间放到文件系统的子目录中,从技术层面来看,命名空间只是PHP中的一种记号,PHP解释器会将其作为前缀添加到类、接口、函数和常量的名称前面。

【摘录】【为什么使用命名空间】:命名空间很重要,因为代码放在沙盒中,可以和其他开发者编写的代码一起使用。这是现代PHP组件生态系统的基础。组件和框架的作者编写了大量的代码,供众多的PHP开发者使用,这些作者不可能知道或控制别人在使用自己的代码时还使用了什么其它类、接口、函数或常量。如果你开发的是小型个人项目,只有少量的依赖,类名冲突可能不是问题。但是如果在团队中工作,开发有许多第三方依赖的大型项目,就要认真对待命名冲突的问题,因为你无法控制项目依赖在全局命名空间中引入的类、接口、函数和常量,这就是为什么要使用命名空间的原因

【官方文档】:http://php.net/manual/zh/language.namespac...
声明命名空间
【声明空间】:命名空间声明语句以 namespace 开头,随后是一个空格,然后是命名空间的名称并且以分号结尾(具体可参考上文的DEMO)

【子命名空间】:子命名空间的声明方式和前面的示例完全一样。唯一的区别是,需要用 \ 把命名空间和子命名空间分开:

# @ 命名空间
namespace TestSpace_01;
# @ 子命名空间
namespace TestSpace_01\TestSpace_02;

【总结】: 在同一个命名空间或子命名空间中的所有类没必要在同一个PHP文件中声明。你可以在PHP文件的顶部指定一个命名空间或者子命名空间,此时这个文件中的代码就是该命名空间或子命名空间的一部分。因此我们可以在不同的文件中编写属于同一个命名空间的多个类
导入和别名
【使用命名空间】:命名空间的默认使用方式只需在实例化对象时加上其命名空间即可

# @ 命名空间
namespace TestSpace_01;
class Test
{
    public function TestPrint()
    {
        var_dump('Hellow World');
    }
}
# @ 导入命名空间中的类
$Obj_Test = new \TestSpace_01\Test();
$Obj_Test -> TestPrint();

【导入命名空间 】:从PHP5.3开始可以导入PHP类、接口和其它命名空间,并为其创建别名。从PHP5.6开始可以导入PHP函数和常量,并为其创建别名。若加载了一些结构复杂的依赖代码就会出现一个问题:类名特别长,通过 use 关键字告诉PHP想要使用的类

# @ 模拟可能出现的多层级的命名空间
namespace TestSpace_01\TestSpace_02\TestSpace_03\TestSpace_04\TestSpace_05;
class Test
{
    public function TestPrint()
    {
        var_dump('Hellow World');
    }
}
# @ 使用默认的命名空间
use TestSpace_01\TestSpace_02\TestSpace_03\TestSpace_04\TestSpace_05;
$Obj_Test = new Test();
$Obj_Test -> TestPrint();

【别名】:如果特别懒,还可以使用别名,只需在导入命名空间时加上 as 跟上别名即可

# @ 使用命名空间,并自定义别名
use TestSpace_01\TestSpace_02\TestSpace_03\TestSpace_04\TestSpace_05\Test as TS;
$Obj_Test = new TS();
$Obj_Test -> TestPrint();

【建议】:应该在PHP文件的顶部使用 use 关键字导入代码,而且要放在<?php标签或命名空间声明语句之后,使用 use 关键字导入代码时无需在开头加上\符号,因为PHP假定导入的是完全限定的命名空间。use关键字必须出现在全局作用域中(即不能在类或函数中),因为这个关键字在编译时使用。不过 use 关键字可以在命名空间声明语句之后使用,导入其他命名空间中的代码

【导入函数&常量】:从PHP5.6开始还可以导入函数和常量,不过要调整 use 关键字的句法。如果想导入函数,要把 use 改成 use func,如果想导入常量,要把 use 改成 use constant

# @ 定义命名空间
namespace TestSpace_01;
# @ 定义方法
function Test_Func()
{
    var_dump("AA");
}
# @ 定义常量
const TEST_CONST = 'BB';
# @ 导入方法与常量,为了区分是通过命名空间调用为其创建别名,并通过别名调用
use function TestSpace_01\Test_Func as Spc_Func;
Spc_Func();
use const TestSpace_01\TEST_CONST as Spc_Constant;
echo Spc_Constant;

【注意】:必须注意的是通过命名空间来引入的常量必须使用 const 关键词来定义,若使用 define 方法来定义则系统会提示使用了未被定义的常量,通过查阅了许多的文档和帖子包括PHP官网,都没有一个正面的解释所以我个人猜测是由于命名空间的作用原理类似于面向对象所以外部使用 define 定义的常量无法被解析,而通过 const 定义的常量则能被正常解析。官网文档:http://php.net/manual/zh/language.constant...

# @ 引入通过 define 关键词定义的常量会提示错误信息
Notice: Use of undefined constant TEST_CONST - assumed 'TEST_CONST' in D:\wamp\www\Test\index.php on line 15

实用技巧
【多重导入】:PHP允许使用简短的导入语法,把多个 use 语句写成一行

# @ 多重导入命名空间使用 "," 隔开
use TestSpace_01\Test_01,
    TestSpace_02\Test_02,    
    TestSpace_03\Test_03,    
    TestSpace_04\Test_04;

【建议】:即使支持简写,但是还是建议一行一个 use 以便阅读,并且最好遵循“一个文件一个命名空间”的最佳实践
全局命名空间
【说明摘录】:如果引用类、接口、函数或常量时没有使用命名空间,PHP假定引用的类、接口、函数或常量在当前的命名空间中。如果这个假定不正确,PHP会尝试解析类、接口、函数或常量。如果需要在命名空间中引用其他命名空间中的类、接口、函数或常量,必须使用完全限定的PHP类名(即 命名空间+类名)。你可以输入完全限定的PHP类名,也可以使用 use 关键字把代码导入当前的命名空间(参考 "导入与别名" 一节中的DEMO)-- O'REILLY《 Modern PHP 》
【特殊情况】:有些代码可能没有命名空间,这些代码在全局命名空间中。PHP原生的 Exception 类就是如此。在命名空间中引用全局命名空间中的代码时,要在类、接口、函数或常量的名称前加上 \ 符号。

# @ 定义命名空间
namespace TestSpace_01;
class Foo
{
    public function DoSomeThing()
    {    # @ 尝试实例化全局命名空间中的 Exception 类
        $exception = new Exception();
    }
}
use TestSpace_01;
$Obj_Foo = new Foo();
$Obj_Foo -> DoSomeThing();
# @ 提示错误:无法找到 Exception 类
Fatal error: Class 'TestSpace_01\Exception' not found in D:\WAMP\www\JustTest\index.php on line 8 

【正确语法】:

# @ 定义命名空间
namespace TestSpace_01;
class Foo
{
    public function DoSomeThing()
    {    # @ 添加 "\" 符号调用全局空间中的类
        $exception = new \Exception();
    }
}
use TestSpace_01;
$Obj_Foo = new Foo();
$Obj_Foo -> DoSomeThing();

【补充】:命名空间还为PHP Framework Interop Group ( PHP-FIG ) 制定的PSR-4自动加载标准奠定了基础。大多数现代的PHP组件都使用了这种自动加载器模式,并且使用Composer,实现自动加载项目的依赖,如果没有命名空间,就不可能出现现代的PHP生态系统和基于组件的新兴架构

【实例】:Symfony是一个优秀的知名框架,你可以再其Httpfoundation组件的github站点中查看其代码,你便会发现现代的PHP组件都采用了命名空间:https://github.com/symfony/http-foundation

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!