php的命名空间

问:命名空间是什么?它有什么用?

 

答:命名空间是一种带有限制性描述的关键词,能说明代码是“混”哪片的。他是在5.3版本中才加入的,这个版本号可以说是个分界点,也就是因为命名空间的存在,很多的开源的代码在安装的时候都会限制php代码大于等于5.3,由此可见命名空间的重要性。它类比到生活中就是“地址”,也可以说是你学籍卡上的地址信息,比如XX学校XX年级XX级部XX班。至于它的作用呢,更多的是发挥解决同名问题,让引用他的代码能够准确找到它。

看一下官方给出来的解释:PHP 命名空间可以解决以下两类问题:

1:用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突

2:为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短) 的名称,提高源代码的可读性。

对于官方的解释,用一个形象化的例子来表达就是:在一个学校里有很多与你同名的同学,此外学校有个严格规定,同名的学生是不允许分配在同一个班级里面的(虽然现实不是,这里是为了更贴切代码中不允许同名函数和类以及常量存在这一情况,而这么设定的),这些同学呢,有的在不同年级有的在不同级部,当然肯定不在一个班里面。那么我们怎么找到他们呢?就是通过学校年级级部班,定位到这也就跑不了你了,当然除了学校还有其他单位,那就可以类比到第三方啦。综上所述,命名空间就是给代码一个地址,让其他代码能够找到,能够进行联系。

 

问:那怎么创建(命名) 一个命名空间呢?有什么要注意的地方么?

 

答:很简单,通过namespace关键字就能命名一个空间。

注意的地方有以下这么几点

1:命名空间首字符不能是数字,必须是字母或者是下划线,否则会报出fatal error。

2:如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间。在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。(例如declare(encoding='UTF-8'); )所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。

3:可以在一个文件中创建多个命名空间,建议对每个命名空间使用{}来以示范围,当然也可以不加,但这样阅读性不好。将全局的非命名空间中的代码与命名空间中的代码组合在一起(在一个文件中),只能使用大括号形式的语法。全局代码必须用一个不带名称的 namespace 语句加上大括号括起来

4:默认情况下,所有常量、类和函数名都放在全局空间下,就和PHP支持命名空间之前一样。

5:define在命名空间内设置的常量默认是全局的

 

问:我看到有的命名空间名称还有\符号,这是干啥的?

 

答:这个看着像不像文件夹的路劲,哈哈,没错,命名空间和文件夹很类似。这东西叫子命名空间,类比就是子文件目录。例如namespace MyProject\Sub\Level;  

 

问:那怎么引用一个命名空间或其下的类呢?

答:引用其实很好引用,只不过在不同的场景下有不同的解析方式需注意。这也就把引用方式分了类:

1:非限定名称。(往往用在use到类名上),没有使用命名空间。

2:限定名称。(往往用在use命名空间),使用时类前面存在命名空间名

3:完全限定名称。是以\开头的,可以有命名空间也可以没有。

注意:命名空间解析方法,除了完全限定名称将会原封不动的按照字面解析,其余的(非限定名称和限定名称)都遵循导入原则(use套路)或者拼接原则(就是所处空间+字面空间)

如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。

这种带命名空间的类都是从库中(也就是有一个基础路径)开始。\只出现在调用和use中。

在命名空间中动态访问其他命名空间元素时,注意因为在动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠是不必要的。这个知识点在框架的自动加载中常常用到。

举个栗子:两个使用命名空间的文件,里面各有一个hello类和sayhello方法。两个文件分别用A、B来表示。假设现在是A引用B,在A中使用非限制性名称,则调用的的是A,当然也可以使用完全限定名称来调用A,限制性名称肯定是无法调用自身的了。那如果在A中调用B的方法呢,可以采用完全限定名称(这个百分百可以)或限制性名称(这个要求路径有相对应关系),如果二者在相同的命名空间下,则可用非限定名称!

访问命名空间中元素的方式(没有use时,对应use时,走use的规则)

1)非限定名称(不带任何前缀)。$obj = new User(),解析为$obj = new current\User()

2)限定名称(带相对空间前缀)。$obj = new Home\User(),解析为$obj = new current\Home\User()

3)完全限定名称(从根空间开始)。$obj = new \Home\User(),解析为$obj = new \Home\User()

 

 

问:怎么访问当前命名空间的元素?

答:有两种方式;

第一种,使用__NAMESPACE__。第二种使用namespace。

 

问:这两种有什么区别么?

答:效果是一样的,只是用法不同。

直接使用namespace就像类中使用self是一样的,放在最前面然后用斜杠拼接上元素全局空间(不带命名空间的)下也可以这样使用。

__NAMESPACE__则是一个魔术常量,它代表这当前代码所在的命名空间下的名称。如果是全局空间(不带命名空间的)这个常量就是空字符串。常用于动态创建名称

 

问:怎么引入别的命名空间呢?又怎么给他起个别名呢?

答:引入用use,起别名用use+as.

事实上,use本身默认了最后一个路径为别名的!

use My\Full\NSname as NSname use My\Full\NSname是一样的;

也可以引入一个全局类,如use \ArrayObject;

 

问:有没有一个综述或者规则来说明这些名称的解析原理?

答:有!官网给总结的就很到位!

名称解析遵循下列规则:(一般就是导入命名空间或其中的类元素)

1:对完全限定名称的函数,类和常量的调用在编译时解析。例如 new \A\B 解析为类 A\B。(就是原封不动

2:所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间 A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。(就是导入原则

3:在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e() 。

4:非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间 A\B\C 导入为C,则 new C() 被转换为 new A\B\C() 。(2的细说)

5:在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数 foo() 的调用是这样解析的:

(1)在当前命名空间中查找名为 A\B\foo() 的函数

(2)尝试查找并调用 全局(global) 空间中的函数 foo()。

----------------------------对于类,没有导入规则的,针对3的细说---------------------------------------

6:在命名空间(例如A\B)内部非限定名称或限定名称(非完全限定名称)的调用是在运行时解析的。下面是调用 new C() 及 new D\E() 的解析过程: 

new C()的解析:

  在当前命名空间中查找A\B\C类。

尝试自动装载类A\B\C。

new D\E()的解析:

在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。

尝试自动装载类 A\B\D\E。 

7:为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C()。

 

最后个人评述:命名空间就是用来组织代码结构的,方便管理还解决冲突。至于常用点就是use和自动加载机制的配合,使得类加载变得无比强大。但对阅读上可能带来一点麻烦,但是读懂了命名空间的原理,也就小意思了。主要在非限定名称和限定名称解析的规则上,这点常用,懂了之后也就没什么了

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值