PHP 面向对象编程和设计模式 (5) - PHP 命名空间的使用及名称解析规则

PHP高级程序设计 学习笔记
2014.06.12

命名空间概述

PHP 在 5.3.0
以后的版本开始支持命名空间。什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:

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

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

PHP 命名空间提供了一种将相关的类、函数和常量组合到一起的途径。下面是一个说明 PHP 命名空间语法的示例:

定义命名空间

虽然任意合法的PHP代码都可以包含在命名空间中,但只有三种类型的代码受命名空间的影响,它们是:类,函数和常量。命名空间通过关键字namespace
来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间。另外,与PHP其它的语言特征不同,同一个命名空间可以定义在多个文件中,即允许将同一个命名空间的内容分割存放在不同的文件中。当然你也可以在同一个文件中定义多个命名空间。


namespace MyProject;

class MyClass
{
#code...
}

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


namespace MyProject\helper\http;

class MyClass
{
#code...
}

在同一个文件中定义多个命名空间:在同一个文件中声明多个命名空间有两种方式,不过在实际编程实践中,非常不提倡在同一个文件中定义多戈命名空间。这种方式的主要用于将多个
PHP 脚本合并在同一个文件中。下面列出第一种方法。


namespace MyProject\helper\http;

class MyClass
{
#code...
}

namespace MyProject\helper\request;

class MyClass
{
#code...
}

不过强烈不建议使用这种方法,可以参考下面的大括号定义法:


namespace MyProject\helper\http;
{
class MyClass
{
#code...
}
}

namespace MyProject\helper\request;
{
class MyClass
{
#code...
}
}

PHP 命名空间中的元素使用

在讨论如何使用命名空间之前,必须了解 PHP 是如何知道要使用哪一个命名空间中的元素的。类名可以通过三种方式引用:

  1. 非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是
    currentnamespace,foo 将被解析为 currentnamespace\foo。如果使用 foo
    的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。
    警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。详情参见
    使用命名空间:后备全局函数名称/常量名称。

  2. 限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或
    subnamespace\foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为
    currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo
    会被解析为subnamespace\foo。

  3. 完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或
    \currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal
    name)currentnamespace\foo。

使用命名空间:别名/导入

允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。PHP 命名空间支持
有两种使用别名或导入方式:为类名称使用别名,或为命名空间名称使用别名。在PHP中,别名是通过操作符 use 来实现的。

注意PHP不支持导入函数或常量。


namespace foo;
use My\Full\Classname as Another;

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

// 导入一个全局类
use \ArrayObject;

名称解析规则

在说明名称解析规则之前,我们先看一些重要的定义:

  1. 非限定名称Unqualified name:名称中不包含命名空间分隔符的标识符,例如 Foo

  2. 限定名称Qualified name:名称中含有命名空间分隔符的标识符,例如 Foo\Bar

  3. 完全限定名称Fully qualified name:名称中包含命名空间分隔符,并以命名空间分隔符开始的标识符,例如 \Foo\Bar。
    namespace\Foo 也是一个完全限定名称。

名称解析遵循下列规则:

  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() 。

  5. 在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数 foo() 的调用是这样解析的:
    1)
    在当前命名空间中查找名为 A\B\foo() 的函数
    2) 尝试查找并调用 全局(global) 空间中的函数
    foo()。

  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。

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

Example 名称解析示例


<?php
namespace A;
use B\D, C\E as F;

// 函数调用

foo(); // 首先尝试调用定义在命名空间"A"中的函数foo()
// 再尝试调用全局函数 "foo"

\foo(); // 调用全局空间函数 "foo"

my\foo(); // 调用定义在命名空间"A\my"中函数 "foo"

F(); // 首先尝试调用定义在命名空间"A"中的函数 "F"
// 再尝试调用全局函数 "F"

// 类引用

new B(); // 创建命名空间 "A" 中定义的类 "B" 的一个对象
// 如果未找到,则尝试自动装载类 "A\B"

new D(); // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
// 如果未找到,则尝试自动装载类 "B\D"

new F(); // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象
// 如果未找到,则尝试自动装载类 "C\E"

new \B(); // 创建定义在全局空间中的类 "B" 的一个对象
// 如果未发现,则尝试自动装载类 "B"

new \D(); // 创建定义在全局空间中的类 "D" 的一个对象
// 如果未发现,则尝试自动装载类 "D"

new \F(); // 创建定义在全局空间中的类 "F" 的一个对象
// 如果未发现,则尝试自动装载类 "F"

// 调用另一个命名空间中的静态方法或命名空间函数

B\foo(); // 调用命名空间 "A\B" 中函数 "foo"

B::foo(); // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
// 如果未找到类 "A\B" ,则尝试自动装载类 "A\B"

D::foo(); // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法
// 如果类 "B\D" 未找到,则尝试自动装载类 "B\D"

\B\foo(); // 调用命名空间 "B" 中的函数 "foo"

\B::foo(); // 调用全局空间中的类 "B" 的 "foo" 方法
// 如果类 "B" 未找到,则尝试自动装载类 "B"

// 当前命名空间中的静态方法或函数

A\B::foo(); // 调用命名空间 "A\A" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\A\B" 未找到,则尝试自动装载类 "A\A\B"

\A\B::foo(); // 调用命名空间 "A\B" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
?>

PHP 面向对象编程和设计模式 (5) - PHP 命名空间的使用及名称解析规则,布布扣,bubuko.com

时间: 2024-12-22 18:08:06

PHP 面向对象编程和设计模式 (5) - PHP 命名空间的使用及名称解析规则的相关文章

命名空间--名称解析规则

(PHP 5 >= 5.3.0, PHP 7) PHP 命名空间中,类名可以通过三种方式引用: 非限定名称(Unqualified name),名称中不包含命名空间分隔符的标识符,如Foo. 例子 $a=new foo(); 或 foo::staticmethod();.如果当前命名空间是currentnamespace,foo 将被解析为currentnamespace\foo.如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo. 限定名称(Quali

PHP 面向对象编程和设计模式 (1/5) - 抽象类、对象接口、instanceof 和契约式编程邹渍祝揍缀踪

http://www.ebay.com/cln/lv1_ldhb/2015.01.29/166849938013 http://www.ebay.com/cln/nh5_jvtj/2015.01.29/166849932013 http://www.ebay.com/cln/j7d_rvpx/2015.01.29/166855853011 http://www.ebay.com/cln/xjh_hjrf/2015.01.29/166674518014 http://www.ebay.com/cl

PHP 面向对象编程和设计模式 (2/5) - 静态变量、属性和方法及延迟绑定追嘴坠缀自壮

http://www.ebay.com/cln/77f_flrb/2015-01-29/166649677018 http://www.ebay.com/cln/7lh_nprn/2015-01-29/166579847017 http://www.ebay.com/cln/ttb_vbnb/2015-01-29/166693228012 http://www.ebay.com/cln/fzf_bblf/2015-01-29/166841922013 http://www.ebay.com/cl

PHP 面向对象编程和设计模式 (4/5) - 异常的定义、扩展及捕获最撞自走赘奏

http://www.ebay.com/cln/jz9_rrjl/2015-01-28/165376418015 http://www.ebay.com/cln/lpt_vpdv/2015-01-28/165264294013 http://www.ebay.com/cln/n5j_zxpr/2015-01-28/165101821012 http://www.ebay.com/cln/jz9_rrjl/2015-01-28/165376423015 http://www.ebay.com/cl

面向对象编程思想(前传)--你必须知道的javascript(转载)

原文地址:http://www.cnblogs.com/zhaopei/p/6623460.html阅读目录 什么是鸭子类型 javascript的面向对象 封装 继承 多态 原型 this指向 call apply band js中的闭包 什么是高阶函数 在写面向对象编程思想-设计模式中的js部分的时候发现很多基础知识不了解的话,是很难真正理解和读懂js面向对象的代码.为此,在这里先快速补上.然后继续我们的面向对象编程思想-设计模式. 什么是鸭子类型 javascript是一门典型的动态类型语

面向对象编程中的设计模式

面向对象编程中的设计模式 最近在复习(预习)软考,看到了设计模式这个知识点,打算小做总结一下~~ 设计模式分为三种类型,共23种.(红色标注常用的) 创建型模式:单例模式.抽象工厂模式.建造者模式.工厂模式.原型模式. 结构型模式:适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模式. 行为型模式:模版方法模式.命令模式.迭代器模式.观察者模式.中介者模式.备忘录模式.解释器模式(Interpreter模式).状态模式.策略模式.职责链模式(责任链模式).访问者模式.

面向对象编程——设计模式之一

一.面向对象 面向对象,就是将一些属性和行为封装成对象,对于使用者来说不用关心对象的内部具体实现,只管调用它公开的属性方法就行了.同一类型的对象抽象出来就是类.类是对象的模板. 面向对象编程,共三步: 1.设计系统的类和接口: 2.设计类和接口的方法和属性: 3.建立类类和接口之间的关系(继承.实现.依赖.关联(聚合.组合关系)): 类和接口之间的关系请参考:http://www.cnblogs.com/liuling/archive/2013/05/03/classrelation.html

JavaScript设计模式:一、面向对象编程

JavaScript面向对象编程 众所周知,JS作为一门脚本语言,由于其设计者在设计JS的时候,也仅仅用了很少的时间就完成了JS这门语言的创建,JS虽然拥有着脚本语言的优势,但是JS也存在着天生的缺陷.其中之一就是:"没有完整的面向对象和自定义类型支持",这是因为JS本身没有很好的模块化.但事实上是,很多JS学习者或者使用者的共同点是:他们接触的第一门编程语言大都是C++或者Java这种老牌OOP语言,写代码时都是秉持着面向对象的思想,这在学习JS或者使用JS不免会感到有一些难受. 那

JavaScript设计模式:一、面向对象编程(第三节)

一.继承 js并没有继承这一个现有的机制,所以我们所说的继承是通过JS本身的机制去实现的. 1.类式继承 1 // 类式继承 2 3 // 父类 4 function SuperClass () { 5 this.superValue = true 6 } 7 8 // 为父类原型添加方法 9 SuperClass.prototype.getSuperValue = function (arguments) { 10 return this.superValue 11 } 12 13 // 声明