PHP 命名空间
1. PHP中的命名空间是什么?
官方解释在此: 命名空间概述
命名空间用一句话说,就是:把 类、函数、变量 等放到逻辑子文件夹中去,以避免命名冲突。
注:命名空间跟实际代码文件在文件系统中的路径没有任何关系,如果你感到迷茫,可以看看本文最后一节。
2. 被隐藏的第一个 \
在每个 PHP 文件的最开始定义命名空间:
<?php namespace TinyLara\TinyRoute; class TinyRoute { ... }
在定义命名空间之后引入命名空间:
<?php namespace TinyLara\TinyRoute; use TinyLara\TinyView\TinyView; class TinyRoute { ... }
上述代码中,
namespace TinyLara\TinyRoute use TinyLara\TinyView\TinyView
这两行的真实路径是: \TinyLara\TinyRoute、\TinyLara\TinyView\TinyView,顶级命名空间标识(第一个 \ )被省略了。
3. 被隐藏的别名
在上一节中中,这一行代码
use TinyLara\TinyView\TinyView
的完整写法应该是:
use \TinyLara\TinyView\TinyView as TinyView;
如果不指定别名,那就默认别名为类名。
4. 使用绝对路径直接调用
<?php namespace TinyLara\TinyRoute; class TinyRoute { public function foo() { return \TinyLara\TinyView\TinyView::fuck(); } }
使用绝对路径调用类时顶级命名空间标识(第一个 \ )不能省略。(很多人都在这个地方迷惑了)
5. 命名空间的实际价值
命名空间的存在是为了解决下面两个问题:
- 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
- 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。
目前非常流行的 Composer 就是一个基于命名空间的包管理器/依赖管理器,同样,Laravel 能达到今天的成功,很大程度上也是因为PHP5.3的普及,生恰逢时。你可以在 https://packagist.org/ 上下载到各种 composer 包,类似于 yum、npm或者gem。
6. 同一命名空间下的类可以任意相互调用
<?php namespace A; class ClassA { public static function test() { echo 'Success!'; } }
<?php namespace A; class ClassB { public static function test() { ClassA::test(); // 直接调用即可 } }
直接调用即可。
7. 关于代码文件的结构
PSR-4 命名空间规范约定了 PHP 类的命名空间应该和实际在文件系统中的位置一致,而现实中绝大多数 PHP 框架为了方便都采纳了这条规范,最明显的就是 Laravel 4 到 5 的转变。在这种情况下,我发现不少新手又迷茫了,错误地理解了我在上文中的阐述的“路径”的概念。基于此我要简单讲述一下 PHP 运行的基本流程,我相信看完你们就不会再有上面的误解了。
PHP 运行流程
在一个典型的 Apache + mod_php 架构的 PHP 运行环境中,一个 PHP 网站是这样运行的:
- Apache 收到用户的 HTTP 请求
- 这个请求是以 .php 结尾或者是一个不存在的路径(.htaccess 会将其转发到 index.php)
- Apache 的 mod_php 会启动一个新的 PHP 进程(PHP 解释器),读取 HTTP 请求的 URL 中的那个 .php 文件或者 index.php
- 被读取进 PHP 解释器的字符串被按照 PHP 的语法进行解析。为了方便理解,我们将这些经过解析的字符串所生成的 context(上下文)命名为 Matrix
- 然后 PHP 解释器会根据从 Matrix 中解析出的特定 PHP 语句(如 require)载入其他 PHP 文件,并将其内容以字符串的形式加入 Matrix
- 最终 Matrix 变成一个数万行代码的巨型上下文(为了便于理解可以想象成巨长的代码文件字符串),PHP 解释器会按照 PHP 语法执行 Matrix,进行数据库连接、网络请求、文件读写等操作
- 每一次的 echo 都会被写入到输出缓冲区,最终这个巨长的代码字符串被执行完毕,PHP 进程退出内存
- 缓冲区中就是要发给用户的 HTTP response,其实就是一堆字符串,只不过它遵守 HTML 规范,可以被浏览器解析。这一堆字符串被 Apache 发送回用户的浏览器,浏览器渲染,用户看到内容
命名空间在哪里?
命名空间从始至终就是一个“内部伪概念”,只是用于解决类和变量的命名冲突,从来就跟实际文件结构没有半毛钱的关系。让大家疑惑的其实是自动加载,当它和命名空间混杂在一起的时候,就不容易理解了。命名空间从来就是一个纯 PHP 内部的概念,你可以把整个 Laravel 框架的所有文件合并成一个巨大的 PHP 文件,取消自动加载,除了性能会损失一些,功能不会受到任何影响,命名空间依旧运转良好。