+ -
当前位置:首页 → 问答吧 → php5.3.0 开始 命名空间 手册翻译

php5.3.0 开始 命名空间 手册翻译

时间:2008-07-01

来源:互联网

边学习边翻译了手册上的PHP命名空间的东西,本人E文不是很好。大家只做了解看看。  原文在我的BLOG:laoniphp.com




命名空间概括:
在PHP里设计命名空间的这个概念是在最大的程度上解决PHP类库的有效范围问题。在PHP中,所有定义的类的都属全局范围的。于是,如果有个 PHP库开发人员想开发个公共模块或是一个公共的类库接口,那么他必须知道,在其他PHP公共类库中存在的相同功能,因此要选择一个独一无二的类名。这样才能让自己写的类和其他类很好的工作在一起。通常,就是用独特的前缀名加类名来解决这个问题。比如数据库类的名定义可能是这样的 My_Library_DB,也就因为这样导致了很长的类名
命名空间允许开发人员在不使用类前缀这样的方式也能管理名字作用域,和不造成难读的代码的同时解决公共域问题。
命名空间在PHP 5.3.0中可用.
命名空间定义
命名空间使用namespace 关键字 来定义,它应该在文件的开始被定义(译者话:文件的第一行),例如:
<?php
namespace MyProject::DB; const

CONNECT_OK = 1; class

Connection { /* … */ } function

connect() { /* … */ }
?>
同个命名空间名 可以使用在多个不同的文件里。
命名空间里可以包含 类 、常量、函数,不能包含其他零散代码。
定义命名空间后产生如下作用:
1. 在命名空间里所有的类、函数、常量自动加上命名空间名作为它们名字的前缀。类总使用完成名字。比如上面例子的类 将这样被调用:MyProject::DB::Connection.
2. 创建的常量它的名字是由命名空间的名字加上常量名,象类常量、命名空间常量只能是静态常量。
3.不符合规则的类名(比如没有包含::),在脚本解释的时候将遵循这样的规则:
1. 先在当前命名空间里寻找类(当前命名空间名字最前缀的),不尝试autoload。
2.  在全局域里面寻找类,不尝试autoload。
3. 当前命名空间被试图自动载入
4. 上面如果查找错误,就查询失败
4. 不符合规则的函数名(比如没有包含::),在脚本运行开始首先查找当前命名空间,然后查找全局域空间。
5. 不符合规则的常量名,在脚本运行开始先查找当前命名空间,然后查找全局域空间
引用命名空间
在命名空间中任何时候每个类和函数都可以通过完整类名来引用,比如:MyProject::DB::Connection or MyProject::DB::connect
<?php
require ‘MyProject/Db/Connection.php’;
$x = new MyProject::DB::Connection;
MyProject::DB::connect();
?>
使用use 操作符可以把命名空间导入到当前上下文中(命名空间域或是全局域)。使用如下:
<?php
/* … */
use Some::Name as Othername;
// The simplified form of use:
use Foo::Bar;
// which is the same as :
use Foo::Bar as Bar;
?>
导入命名空间按照如下工作:
在脚本运行的时候遇到本地名othername(as 本地名 或者 使用::来分搁) 都会用 some::Name
来替换
use 只能使用在全局域里面,不能在类或函数里面使用。命名空间的有效范围是从import 导入到当前文件尾部。在文件的开始地方导入命名空间可以避免作用域的混淆。
导入和访问命名空间
<?php
require ‘MyProject/Db/Connection.php’;
use MyProject::DB;
use MyProject::DB::Connection as DbConnection;
$x = new MyProject::DB::Connection();
$y = new DB::connection();
$z = new DbConnection();
DB::connect();
?>
导入操作发生在编译时期,所有的局部命名都将被转换为它的全名。不过编译器不会转换字符窜中的名称,所以回调函数不能依赖导入规则
全局域
当没有定义命名空间的时候,所有类和函数的作用域是在全局。使用::做前缀引用类、函数,是指明从全局域里引用,甚至从命名空间上下文来引用。
<?php
namespace A::B::C;
/* This function is A::B::C::fopen */
function fopen() {
/* … */
$f = ::fopen(…); // 从全局域调用 fopen
return $f;
}
?>
__NAMESPACE__编译的时候在当前命名空间会定义一个常量__NAMESPACE__ 。 在命名空间外,此常量会是个空值。这个常量是挺有用的,当我们在命名空间里需要使用次命名空间的全名的时候。
<?php
namespace A::B::C; function

foo() {
// do stuff
}
set_error_handler(__NAMESPACE__ . “::foo”);
?>
命名解决方案
命名会按照下面这些规则进行转换
1.在编译的时候,完整修饰名( All qualified names)会根据导入规则来对全部及格的名字进行转换。例如:如果命名空间A:B:C被导入。那么调用B:C:e() 就被解释成 A:B:C:e()。
2.在编译的时候,不完整修饰名( Unqualified class names)会根据当前的导入规则进行转换(使用完整名来替换短名)例如:如果命名空间A:B:C被导入,new c() 被翻译成 new A:B:c()
3.在当前命名空间里调用在命名空间里定义的不完整修饰名函数时候,在编译的时候会根据当前命名空间的函数来解释。
4.在命名空间里面(比如:A::B),调用一个在当前命名空间里面的不具有完整修饰名的函数而且没有在当前命名空间定义的,具体调用那个函数在运行的时候决定。下面是在运行的时候怎样去调用函数 foo():
1.从当前命名空间里寻找A::B::foo()
2.尝试调用PHP内部函数foo()
在命名空间里调用全局域里的用户定义的函数,应该使用::foo()
5.在命名空间里面(比如:A::B),调用一个在当前命名空间里面的不具有完整修饰名的类。下面是在运行的时候怎样去调用new c():
1.从当前的命名空间里面寻找类 A::B::C
2.尝试调用PHP内部类
3.试图去autoload 自动加载类A::B::C

引用全局域的类,请使用 :: new C()


6.调用一个完整修饰名的函数的时候,在运行时候怎么选择引用呢。下面就是A::B::foo() 的引用步骤

1.在A::B 命名空间下寻找函数foo()
2.寻找类A::B 同时调用它的静态方法foo().如果成功将自动加载

7.调用完整修饰名的类的时候,是在运行的时候才按照想对应的命名空间来加载。比如 new A::B::C() 它是引用 命名空间是A::B下的C() 类

<?php
namespace A;
// function calls
foo(); // first tries to call “foo” defined in namespace “A”
// then calls internal function “foo”
::foo(); // calls function “foo” defined in global scope // class references

new B(); // first tries to create object of class “B” defined in namespace “A”
// then creates object of internal class “B”
new ::B(); // creates object of class “B” defined in global scope // static methods/namespace functions from another namespace

B::foo(); // first tries to call function “foo” from namespace “A::B”
// then calls method “foo” of internal class “B”
::B::foo(); // first tries to call function “foo” from namespace “B”
// then calls method “foo” of class “B” from global scope // static methods/namespace functions of current namespace

A::foo(); // first tries to call function “foo” from namespace “A::A”
// then tries to call method “foo” of class “A” from namespace “A”
// then tries to call function “foo” from namespace “A”
// then calls method “foo” of internal class “A”
::A::foo(); // first tries to call function “foo” from namespace “A”
// then calls method “foo” of class “A” from global scope
?>

作者: 逆雪寒   发布时间: 2008-07-01

老逆现在是两头跑啊

作者: spjhf   发布时间: 2008-07-01

引用:
So do you mean if i want to use a class, i need to do extra two steps?

1) require/include that file
2) use the namespace

What about to add a trigger something like:

function __auto_namespace($names, $class)
{
  if ($class === null)
  {
    set_include_dir(implode('/', $names));
  }
  else
  {
    require_once implode('/', $names).'/'.$class.'.php';
  }
}

Then when we:
use NAMESPACE1::NAMESPACE2;
or
use NAMESPACE1::NAMESPACE2::CLASS1;

php could auto include the file we needed without ugly __autoload.
[ 本帖最后由 yarco4 于 2008-7-1 16:16 编辑 ]

作者: yarco4   发布时间: 2008-07-01

个人认为应该加入这个机制. 否则和python的import相比就有点累赘了

作者: yarco4   发布时间: 2008-07-01

命名空间可是杀手级特性

有了这个,PHP又向企业级应用迈进了一大步!

作者: ShiningRay   发布时间: 2008-07-01

  我也比较喜欢python 。  python 十分不错的语言

作者: 逆雪寒   发布时间: 2008-07-02