详细解读php的命名空间(一)


Posted in PHP onFebruary 21, 2018

php的命名空间功能已经出来很久了,但是一直以来没怎么深究过,这次赶着有时间所以特意翻着手册做一个整理和总结帮助自己完善完善,原本准备一篇写完,但发现内容其实还是蛮多的,放一起太长看着累,所以分两篇博客要好些。

一:命名空间概念:命名空间是一种封装事物的方法,类似于目录和文件。

命名空间解决的问题(手册上也写的很清楚,下面按照自己的理解简化了):

1:解决程序编写者自己写的类、常量、函数和php内部的或者第三方的出现名称冲突的情况。

2:创建别名,帮助解决类、常量、函数名称过长的情况,帮助提高代码的可读性,另外名称过长其实通常都是因为为了缓解第一类问题导致的。

二:如何定义命名空间

1:命名空间用关键字namespace声明,同时命名空间必须位于其他代码之前,包括任何非php代码以及空白符(php的declare关键字除外),否则会抛出一个fatal error。

例如:

<?php 
namespace Index; 
?>

注意1:如果命名空间namespace前没有任何代码及空白符,但还是出现fatal error,这个应该是由于bom头导致的,去掉bom头就可以了。
注意2:在命名空间下,虽然可以放置所有合法的php代码,但是受命名空间影响的仅有类(抽象类以及traits)和接口、常量和函数。

2:与目录和文件的关系很象,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义,分隔符是\。

例如:

<?php 
namespace Index\Col\File; 
define('MESSAGE','hello world'); 
?>

3:一个文件中可以定义多个命名空间,定义的语法有两种,一种是简单组合语法,另一种是大括号形式语法,另外一个文件定义多个命名空间的使用一般是多个文件合并成一个文件的场景,但不到万不得已最好不要这样,因为这样增加了代码的复杂度,可读性会降低,一般情况也没有这种使用的必要

简单组合语法:

<?php 
namespace Index; 
const INSTANCE=1; 
 
namespace Col; 
const INSTANCE=2; 
?>

大括号语法,一个文件多个命名空间,如果还需要写上非命名空间的代码,就只能用大括号语法,并且非命名空间代码用namespace声明一个没有名称的命名空间,再用大括号即可:

<?php 
/*命名空间Index*/ 
namespace Index{ 
  const INSTANCE=1; 
} 
 
/*命名空间Col*/ 
namespace Col{ 
  const INSTANCE=2; 
} 
 
/*全局非命名空间代码*/ 
namespace { 
  const INSTANCE=3; 
} 
?>

4:多个不同的文件可以定义同一个命名空间,也就是说同一个命名空间的内容可以分别存储到多个不同的文件中,这里就不举例了。

三:命名空间的识别原理

命名空间的使用原理有三种情况,手册上其实说的详细但可能因为翻译问题导致一些凌乱,这里我简化一下用自己的例子梳理一下:

1:没有限定名称,也就是直接使用要读取的类、常量、函数、接口名称,这种情况会读取该内容所属的命名空间的类、常量、函数、接口名称,但如果命名空间内没有相关的数据,如果是类和接口名称会返回fatal error,如果是函数和常量会自动读取全局的函数和常量,如果全局中也没有,才会报fatal error。

下面举例:

<?php 
/*全局非命名空间代码*/ 
namespace { 
  const INSTANCE=1; 
 
  function test(){ 
    echo 1; 
  } 
 
  class foo{ 
    static function fool(){ 
          echo 1; 
        } 
  } 
 
  var_dump(INSTANCE);   //打印出来的是1 
 
  test();       //输出1 
 
  foo::fool();      //输出1 
 
} 
 
/*命名空间Index*/ 
namespace Index{ 
  const INSTANCE=2; 
 
  function test(){ 
    echo 2; 
  } 
 
  class foo{ 
    static function fool(){ 
          echo 2; 
        } 
  } 
 
  var_dump(INSTANCE);   //打印出来的是2 
 
  test();     //输出2 
 
  foo::fool();    //输出2 
} 
 
/*命名空间Col*/ 
namespace Col{ 
  const INSTANCE=3; 
 
  function test(){ 
    echo 3; 
  } 
 
  class foo{ 
    static function fool(){ 
          echo 3; 
        } 
  } 
 
  var_dump(INSTANCE);   //打印出来的是3 
 
  test();     //输出2 
   
  foo::fool();    //输出2 
} 
?>

上面的例子每个命名空间里输出的都没有限定名称,所以会得到当前命名空间下设置的对应数据值。

如果当前命名空间没有设置,函数和常量则会读取全局设置的对应数据值,全局没有对应的才会报fatal error,类和接口都会直接报fatal error,如下面代码所示。

<?php 
/*全局非命名空间代码*/ 
namespace { 
  const INSTANCE=1;  
  function test(){ 
    echo 1; 
  } 
 
  class foo{ 
    static function fool(){ 
          echo 1; 
        } 
  } 
 
  var_dump(INSTANCE);   //打印出来的是1  
  test();     //输出1  
  foo::fool();    //输出1  
} 
 
/*命名空间Index*/ 
namespace Index{ 
  var_dump(INSTANCE);   //打印出来的是1  
  test();     //输出1  
  foo::fool();    //fatal error 
 
} 
?>

2:限定名称,分为两种情况,一种是包含前缀的限定名称情况,一种是包含全局限定名称的情况。手册上将这两种单独分开了,但我觉得这两种可以合并成一起说,他们都是有限定名称,只是前者没有全局限定,后者有全局限定。

①包含前缀的限定名称,这种前缀可以有多个或者一个层级,但最左侧不能为\全局限定词,这种情况会读取该代码所在命名空间加上该前缀限定名称所对应数据,也就是:

所处命名空间\前缀限定\名称来读取,如果该代码是全局没有命名空间的,则直接用前缀限定名称来读取,也就是:前缀限定\名称来读取。

实例代码:

<?php 
/*命名空间Col\Index*/ 
namespace Col\Index{ 
  const INSTANCE=1; 
} 
 
/*命名空间Index*/ 
namespace Index{ 
  const INSTANCE=2; 
} 
 
/*命名空间Col*/ 
namespace Col{ 
  const INSTANCE=3; 
  var_dump(Index\INSTANCE); //打印出来的是1 读取的是Col\Index\INSTANCE 
} 
 
/*全局非命名空间代码*/ 
namespace { 
  const INSTANCE=4; 
  var_dump(Index\INSTANCE); //打印出来的是2 读取的是Index\INSTANCE 
} 
 
?>

②全局限定前缀名称:也就是在最左侧有全局操作符\进行修饰的前缀限定名称,当然也可以没有前缀限定直接全局操作符\加上名称也是可以的。但加上全局操作符后就跟目录里的绝对路径一样,只会按照全局限定后的所设置的进行读取。

具体实例如下:

<?php 
/*命名空间Col\Index*/ 
namespace Col\Index{ 
  const INSTANCE=1; 
} 
 
/*命名空间Index*/ 
namespace Index{ 
  const INSTANCE=2; 
} 
 
/*命名空间Col*/ 
namespace Col{ 
  const INSTANCE=3; 
  var_dump(\Index\INSTANCE); //打印出来的是2 读取的是Index\INSTANCE 
} 
 
/*全局非命名空间代码*/ 
namespace { 
  const INSTANCE=4; 
  var_dump(\Index\INSTANCE); //打印出来的是2 读取的是Index\INSTANCE 
} 
 
namespace Lin{ 
  const INSTANCE=5; 
  var_dump(\INSTANCE); //打印出来的是4 读取的是INSTANCE,是全局非命名空间里的INSTANCE,如果没有全局操作符\,读取的会是当前命名空间的Lin\INSTANCE=5 
} 
 
?>

四:命名空间在字符串中的转义

有时候命名空间会放在字符串中使用,如果是单引号不会通过编译器解释,所以没有任何问题,但是如果是双引号,那么就会有些意外情况了,要知道双引号里的内容是需要经过编译器进行解释然后再进行输出的,而\在编译器里的解释容易造成歧义

例如"index\name"这里就有\n会被解释成换行,除此之外还有很多这种造成意外的情况。

因此一般我们推荐命名空间如果要放在字符串中使用,最好使用单引号,一是效率,二是安全,如果使用双引号,则必须增加一个\进行转义避免歧义,例如"index\\name"这样就没有问题了。

随手双引号的举个例子:

<?php 
/*全局非命名空间代码*/ 
namespace Index\Name{ 
  class foo{ 
    function __construct(){ 
      echo 2; 
    } 
  } 
} 
 
namespace{ 
  $a= "Index\\Name\\foo"; //用\转义了\所以可以正常运行,但是如果去掉转义的话会报错Class 'Index\Nameoo',因为/f被解释成了换页符 
  $obj=new $a; 
}

这部分碍于篇幅就暂时到这里了,下一篇主要总结命名空间里的namespace和__NAMESPACE__的使用,以及别名的使用等。

PHP 相关文章推荐
基于PHP常用字符串的总结(待续)
Jun 07 PHP
编译php 5.2.14+fpm+memcached(具体操作详解)
Jun 18 PHP
使用PHP获取当前url路径的函数以及服务器变量
Jun 29 PHP
php对数组排序代码分享
Feb 24 PHP
php时间计算相关问题小结
May 09 PHP
php同时使用session和cookie来保存用户登录信息的实现代码
May 13 PHP
深入浅析PHP的session反序列化漏洞问题
Jun 15 PHP
浅谈Yii乐观锁的使用及原理
Jul 25 PHP
PHP实现网站访问量计数器
Oct 27 PHP
实例讲解通过​PHP创建数据库
Jan 20 PHP
PHP实现的敏感词过滤方法示例
Mar 06 PHP
php中try catch捕获异常实例详解
Aug 06 PHP
thinkphp5 migrate数据库迁移工具
Feb 20 #PHP
Laravel 5.4.36中session没有保存成功问题的解决
Feb 19 #PHP
自写的利用PDO对mysql数据库增删改查操作类
Feb 19 #PHP
PHP实现QQ、微信和支付宝三合一收款码实例代码
Feb 19 #PHP
浅析PHP数据导出知识点
Feb 17 #PHP
PHP 应用容器化以及部署方法
Feb 12 #PHP
PHP使用Redis长连接的方法详解
Feb 12 #PHP
You might like
利用PHP制作简单的内容采集器的原理分析
2008/10/01 PHP
CURL的学习和应用(附多线程实现)
2013/06/03 PHP
smarty模板中拼接字符串的方法
2014/02/14 PHP
Use Word to Search for Files
2007/06/15 Javascript
基于jQuery实现下拉收缩(展开与折叠)特效
2012/12/25 Javascript
通过JQuery实现win8一样酷炫的动态磁贴效果(示例代码)
2013/07/13 Javascript
JS的数组迭代方法
2015/02/05 Javascript
javascript实现dom动态创建省市纵向列表菜单的方法
2015/05/14 Javascript
JavaScript实现LI列表数据绑定的方法
2015/08/04 Javascript
css如何让浮动元素水平居中
2015/08/07 Javascript
angular.bind使用心得
2015/10/26 Javascript
jquery 仿锚点跳转到页面指定位置的实例
2017/02/14 Javascript
原生JS实现自定义滚动条效果
2020/10/27 Javascript
快速将Vue项目升级到webpack3的方法步骤
2017/09/14 Javascript
Vue数据双向绑定的深入探究
2018/11/27 Javascript
微信小程序之侧边栏滑动实现过程解析(附完整源码)
2019/08/23 Javascript
js+canvas实现简单扫雷小游戏
2021/01/22 Javascript
解决await在forEach中不起作用的问题
2021/02/25 Javascript
使用python提取html文件中的特定数据的实现代码
2013/03/24 Python
编写Python爬虫抓取暴走漫画上gif图片的实例分享
2016/04/20 Python
django 常用orm操作详解
2017/09/13 Python
PyQt5实现简易计算器
2020/05/30 Python
Python3内置模块之json编解码方法小结【推荐】
2020/12/09 Python
python中的协程深入理解
2019/06/10 Python
微信公众号token验证失败解决方案
2019/07/22 Python
PUMA澳大利亚官方网站:德国运动品牌
2018/10/19 全球购物
Ootori在线按摩椅店:一家专业的按摩椅制造商
2019/04/10 全球购物
DELPHI面试题研发笔试试卷
2015/11/08 面试题
文明学生标兵事迹
2014/01/21 职场文书
关于祖国的演讲稿
2014/05/04 职场文书
教育项目合作协议书格式
2014/10/17 职场文书
常住证明范本
2015/06/23 职场文书
《时代广场的蟋蟀》读后感:真挚友情,温暖世界!
2020/01/08 职场文书
CSS3 天气图标动画效果
2021/04/06 HTML / CSS
Python还能这么玩之只用30行代码从excel提取个人值班表
2021/06/05 Python
MySQL的Query Cache图文详解
2021/07/01 MySQL