php命名空间简介

如下是我对命名空间的一些体会和理解,最好先看下php的官方文档再来看此文,会更好一点。因为水平有限,文中若有纰漏,但愿指出php

前言

在php5.3以上的版本中,php引入了命名空间(如下称呼为namespace)这个性能。我的认为,这是很是重要的一项改变。之因此说重要,并非说namespace自己有多么牛逼或者多高的技术含量。而是因为命名空间的引入,引发了一些列的连锁反应,这些连锁反应给咱们如今phper开发者提供了另外一种可能。linux

如今的开发方式程序员


咱们在以往开发应用的时候,即便是很是简单的应用,也常用php的那些框架,他们一般很重、很大、很难学,更要命的是,还不少,什么Yii二、Thinkphp、CI、ZendFrame、Laravel......好吧我不想说了。windows

另外一种可能composer


如今呢,咱们彷佛有了另一种选择。依靠composer包管理工具,加载packagist上面那些优秀的组件,而后经过composer提供的自动加载机制,将组建应用到项目中去。咱们的开发彷佛变成了摆积木,咱们要作的事情只是将组件恰当的组合起来,怎么样,听着是否是很心动是么?全世界优秀的轮子随我用,这个feel倍爽!!!哦,离题有点远了,那么这和本文的主题namespacey又有什么关系呢?固然有关系了,自动加载的基石namespace框架

实现另一种可能很重要的一步就是,将packagist组件自动加载到应用中。因为php的_autoload有各类各样的实现方式,为此php-fig(php framework interop group一个php组织)提出了psr-0(已经废弃)和psr-4,这两个专门自动加载的解决方案,其核心思想就是:将命名空间和实际的磁盘物理路径创建映射函数

(ps : 到目前为止spr-0、spr-4只是推荐的自动加载解决方案,并无强制,但事实上,基本都采用了这种自动加载方式。除了spr-和spr-4外,composer还支持file 和classmap的方式)工具

为何会有命名空间,它解决了什么问题?

命名空间出现的根本缘由是为了解决命名冲突的问题,我的认为主要是为了解决如下命名冲突性能


  1. 用户自定义的接口/类/trait/函数/常量 同 php系统提供的 接口/类/trait/函数/常量命名冲突
  2. 用户自定义的接口/类/trait/函数/常量 同 第三方框架提供的 接口/类/trait/函数/常量命名冲突

举个例子ui


咱们常用var_dump进行断点调试,这个是系统提供给咱们的内置函数。可是呢,有的程序员对var_dump输出的数据格式不是很满意,但愿本身写一个var_dump函数(var_dump用时间长了,叫其余的名字不习惯),本身格式化其输出信息,可是报错!

<?php
//namespace mydubug;
//若是将上面一行的注释打开就不会再报错,只不过调用的时候须要使用mydebug\var_dump的形式了

function var_dump($message)
{
    echo "<br/>========================================</br>"
    echo $message;
    echo "<br/>========================================</br>"
}

/**
 * 报错信息:PHP Fatal error:  Cannot redeclare var_dump()
 */

命名空间的一些基础概念?

我将采用类比的方法来讲明这些高深的概念,尽可能能让你们清楚。

全局命名空间


接触过linux系统的同窗都应该知道根目录"/"吧,咱们能够将全局命名空间想象为linux的根目录,在该目录下存放的都是php自己提供的各类接口/类/trait/函数/常量。

彻底限定名称


以全局命名空间为前缀的名称,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();咱们能够将其类比为绝对路径

限定名称


不以全局命名空间为前缀的名称,例如,$a = new subnamespace\foo();或subnamespace\foo::staticmethod();咱们能够将其类比为相对路径

非限定名称


不包含任何前缀的名称,例如, $a=new foo(); 或 foo::staticmethod();咱们能够将其类比一个问文件名称或者目录名称

php中的那些要素会受到命名空间的影响?

首先确定一点,并非全部的元素都受到命名空间的影响,好比说变量就不会,只有如下php要素会受到影响:

  • 类(class)
  • 接口(interface)
  • trait
  • 常量(constant)
  • 方法名(function,我认为object里面的方法是method)

什么是别名/导入?命名空间的解析规则是什么?二者又有什么关系?

什么是别名/导入?

咱们能够认为别名/导入,相似是windows下的快捷方式或者是linux下的软链,经过该快捷方式咱们能够连接到,别的空间下的class、interface、trait、constant、function,甚至能够是单纯的链接到别的命名空间而不特指该空间下的任何元素。下面举个例子

<?php
namespace foo;
use My\Full\Classname as Another;

// 下面的例子与 use My\Full\NSname as NSname 相同
use My\Full\NSname;

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

当咱们的代码中有以别名打头的状况时,php就会尝试连接到别名对应的命名空间中的元素,或是别名对应的命名空间,而后拼接剩余的名称,若是有的话。例子中NSname\subns\func(); 检查到NSname是别名,因此先连接到MyFullNSname, 而后拼接剩余名称My\Full\NSname\subns\func();

(ps:导入的名称必须是彻底限定的,不会根据当前的命名空间做相对解析,前导的反斜杠是没必要要的也不推荐的)

命名空间的解析规则是什么?

一图胜千言,仍是上图吧

clipboard.png

从图中,能够看出主要是从彻底限定名和非彻底限定名这两块进行分析的。

二者的关系是什么?

由上图,咱们能够知道,限定名称和非限定名称的解析都会受到别名的影响。
并且,别名的优先级比当前命名空间的优先级高(不少地方都没有说)
也就是说,在一个命名空间下,限定名称和非限定名称会先尝试寻找别名替换,若是找不到对应的别名,才会将当前的命名空间追加到如今的名字前面组成彻底限定名

<?php
//b.php文件
namespace Test\Top;
class B
{
    public function Test()
    {
        echo __FILE__, "\r\n";
    }
}

<?php
//a.php
namespace Top;
use Test\Top as Top;
require __DIR__ . DIRECTORY_SEPARATOR . 'b.php';
Class B
{
    function Test()
    {
        echo __FILE__,"\r\n";
    }
}
(new Top\B())->Test();

a.php和b.php两个文件在同一个目录下:在b.php文件中,在namespace Top下面,拥有别名Test\Top as Top,因此new Top\B() 会被解释成 new Test\Top\B(),也就是将别名进行了替换; 而并非new Top\Top\B(),将当前空间名添加到如今的名字前面。因此此时的运行结果是:xxxx/b.php

命名空间的一些易错点,仅我的体会

一、class 、interface 、traits和const 、function尝试执行的加载策略不一样
clipboard.png

二、一个文件中,只有第一个namespace声明命名空间前不能有任何字符,特别是bom头(看不见可是存在),其余的namespace不作限制。

三、namespace自己并不分区大小写,相同名字的namespace认为是同一个空间

<?php
namespace Test{
    function showName()
    {
        echo "This is a test in namespace Test";
    }
}

namespace test{
    function showName()
    {
        echo "This is a test in namespace test";
    }
}
//报错:PHP Fatal error:  Cannot redeclare test\showName()

参考资料

http://php.net/manual/zh/lang...《Modern php》

相关文章
相关标签/搜索