最近学习一下php的命名空间,中文文档不多,搜到一篇英文的,讲的还蛮系统的,特此翻译一下,以备以后查阅,大家有什么高见或更深刻或者 更悟透的见解希望能不吝赐教,晚辈感激不尽。 

原文: http://code.tutsplus.com/tutorials/namespacing-in-php--net-27203

关于PHP对命名空间的支持,这走过了一段崎岖的历程。感谢的是,从PHP5.3起,加入了对命名空间。php的代码结构也因此提升了了许多。但是,我们究竟该怎样使用命名空间呢?

一、什么是命名空间

  “别玩了要去掉前面的反斜杠,当你将一个命名空间存储到一个字符串变量中的时候。”

把命名空间想象成一个抽屉,在这个抽屉里面你可以放各种各样的东西:想一支铅笔、一张纸、等等,这些是属于你的东西。在你的抽屉下面呢是别人的抽屉,他也可以把各种东西放在他的抽屉里面。为了避免互相取错对方的东西,你决定给抽屉贴上标签,这样就很清晰哪个抽屉式属于谁的了。

  以前,没有引入命名空间的时候,开发者们在他们的类中、函数中、常量中使用 下划线 “_”来区分开。这其实等同于给各自的物品贴上标签然后把他们放到同一个大的抽屉中。当然,这至少已经看上去有点结构,不太那么乱了,但是这非常的不高效。

  命名空间可以拯救这一切。你可以在各自的命名空间内定义同名的函数、类、接口、常量,只要他们是在不同的命名空间中,这就不会报错。本质上来说,一个命名空间仅仅是一个有层级的,来标识常规的php代码块的东西。

  “你已经在使用命名空间了”

  有一点很重要你应该记住的,其实你间接的在使用命名空间了,php5.3以后,所有的代码定义,如果没有显示的定义在用户命名的命名空间中,都是默认定义在一个全局的命名空间中的。全局命名空间同样也包含了php的许多内置的函数定义,想echo(),mysql_connect(),和Exception类。因为全局命名空间没有一个独立的标识名字,它通常指的是 全局空间。

  记住,你没有必要一定要使用命名空间。你的php脚本同样可以执行的很好即使没有命名空间,而且加入命名空间也可能不会发生太快。

二、怎样定义一个命名空间

在一个php文件中,一个命名空间的定义应该是一个最前面的声明(php解释器应该第一个遇到的)。注:唯一一个可以在声明一个命名空间之前声明的东西是 declare 声明,仅仅当declare声明了这个脚本文件的编码。

  声明一个命名空间就是使用一个简单的 namespace关键字,命名空间的名字和php 中其他的标识符的命名规范一样。就是只能有字母、数字、下划线组成,而且不能以数字开头。

<?php
namespace MyProject {
// Regular PHP code goes here, anything goes!
function run()
{
echo 'Running from a namespace!';
}
}

如果你想分配一个代码块给全局空间,你使用namespace关键字,但是后面不带名字。

If you want to assign a code block to the global space, you use the namespace keyword without appending a name.  

<?php
namespace{
//Global Space!
}

你可以在同一个文件中定义多个命名空间。

<?php
namespace MyProject{
//
} namespace MySecondProject{
//
} namespace {
//
}

你也可以在多个文件中使用同一个命名空间;文件的包含 处理过程会自动合并他们。因此,一个好的编程实践是在每一文件中只使用一个命名空间,就像你只在一个文件中定义一个类一样。

  命名空间的使用是用来避免命名(定义)冲突的,和进入了更多的灵活性,更好地组织你的代码。

注意一点,命名空间的用来围绕代码块大括号“{}”完全是可选的,你可以不要它。实际上,坚持一个文件一个命名空间的原则,然后省略大括号使你的代码更简洁多了--不需要代码缩进了,代码嵌套。

  子命名空间

命名空间可以遵循一个确定层级(等级),就像你电脑的文件系统中的目录结构一样。子命名空间是非常有用的,来组织你的代码结构。例如:如果你的项目需要访问数据库,你可能想把所有的数据库相关的代码,如数据库异常和链接句柄都放到一个叫做 database的子命名空间中去。

为了维护上的灵活性,将一个子命名空间放到一个子目录中是明智的。这促使了你的代码更加结构化,更容易使用 autoloader自动加载。PHP使用反斜杠 "\”来作为命名空间的分隔符。

// myproject/database/connection.php
<?php
namespace MyProject\Database class Connection {
// Handling database connections
}

 你可以使用很多的子命名空间,只要你喜欢

<?php
namespace MyProject\Blog\Auth\Handler\Social; class Twitter {
// Handles Twitter authentification
}

定义嵌套的子命名空间是不支持的。下面的例子会抛出一个严重的错误“命名空间的声明不能嵌套!”。 

<?php
namespace MyProject {
namespace Database {
class Connection { }
}
}

三、调用命名空间内的代码

如果你实例化一个别的命名空间中的对象,或者调用一个函数,或者使用一个常量,你要使用反斜杠的语法。他们可以从以下三种方式中解析出来。

  • 非限制的名称
  • 限制的名称
  • 完全限制的名称

(1)非限制的名称

这是一个类的名字,函数的名字,或者常量的名字,没有包含对任何命名空间的引用。如果你是刚刚接触命名空间,这是经常使用它们的方式。

<?php
namespace MyProject; class MyClass {
static function static_method()
{
echo 'Hello, world!';
}
} // Unqualified name, resolves to the namespace you are currently in (MyProject\MyClass)
MyClass:static_method()

 (2)限制的名称

这是我们访问子命名空间层级的方式,这种方式要使用反斜杠语法。

<?php
namespace MyProject; require 'myproject/database/connection.php'; // Qualified name, instantiating a class from a sub-namespace of MyProject
$connection = new Database\Connection();

下面的例子抛出了一个严重的错误:“Fatal error: Class 'MyProject\Database\MyProject\FileAccess\Input' not found" .” 

这是因为 Myproject\FileAccess\Input  访问的是相对于你当前所在的命名空间的。

<?php
namespace MyProject\Database; require 'myproject/fileaccess/input.php'; // Trying to access the MyProject\FileAccess\Input class
$input = new MyProject\FileAccess\Input()

 (3)完全限制的命名空间 

非限制的命名空间和限制的命名空间都是相对于你当前所在的命名空间-----相对路径。他们仅仅用于访问他们同一级的或者子级的命名空间。

如果你想访问一个函数、类、或常量,而他们是位于更高一级的命名空间中,这时候你就要使用完全限制的命名空间----绝对路径而不是相对路径。这就需要在你的调用前面加上反斜杠“\”.这就会让PHP知道调用时要从全局空间开始解析而不是相对路径。 

<?php
namespace MyProject\Database; require 'myproject/fileaccess/input.php'; // Trying to access the MyProject\FileAccess\Input class
// This time it will work because we use the fully qualified name, note the leading backslash
$input = new \MyProject\FileAccess\Input();

没有要求说要在php 的函数内部使用完全限制的名称,通过 一个不限制的名称来调用一个不存在与当前命名空间中的常量或函数时,PHP会自动去全局空间中寻找他们。这个是内置的向后查找,但是这不适用于不限制名称的方式去调用类(也就是说以不限制名称的方式去调用一个不存在与当前命名空间中的类时,PHP不会自动去全局空间中寻找)。在脑子里记住这一点,我们现在可以重载内部的php函数,同时也仍然可以调用原始的函数(或常量)。  

<?php
namespace MyProject; var_dump($query); // Overloaded
\var_dump($query); // Internal // We want to access the global Exception class
// The following will not work because there's no class called Exception in the MyProject\Database namespace and unqualified class names do not have a fallback to global space
// throw new Exception('Query failed!'); // Instead, we use a single backslash to indicate we want to resolve from global space
throw new \Exception('ailed!'); function var_dump() {
echo 'Overloaded global var_dump()!<br />'
}

 动态调用

PHP 是一种动态的编程语言;因此也可以应用这种功能于命名空间的调用上。这本质上类似于实例化变量类 或者 包含变量文件。PHP命名空间的分隔符也是一个元字符。别忘了当你把命名空间存储于一个自动串变量中的时候去掉前面的反斜杠。

<?php
namespace OtherProject; $project_name = 'MyProject';
$package_name = 'Database';
$class_name = 'Connection'; // Include a variable file
require strtolower($project_name . '/'. $package_name . '/' . $class_name) . '.php'; // Name of a variable class in a variable namespace. Note how the backslash is escaped to use it properly
$fully_qualified_name = $project_name . '\\' . $package_name . '\\' . $class_name; $connection = new $fully_qualified_name();

四、namespace 关键字

namespace关键字不仅仅用于定义一个命名空间,它也可以用来解析当前的命名空间,功能上类似于 类中的关键字 self.

<?php
namespace MyProject; function run()
{
echo 'Running from a namespace!';
} // Resolves to MyProject\run
run();
// Explicitly resolves to MyProject\run
namespace\run();

五、__NAMESPACE_常量

很像self关键字,不能用于决定当前所在的类是哪个类,namespace关键字也不能用于决定当前的命名空间是什么命名空间,这就是我们为什么要使用__NAMESPACE__常量。

<?php
namespace MyProject\Database; // 'MyProject\Database'
echo __NAMESPACE__;

这个常量非常的有用,如果你是刚刚开始命名空间的学习,它对于调试也很有帮助。作为一个字符串,它还可以用在动态的代码调用,我们之前说过了。

六、别名或者导入

    “没有必要一定要使用命名空间”

PHP中的命名空间支持导入 importing .导入也叫做 别名。只用类、接口、命名空间可以取别名或者被导入。

导入是非常有用的,也是命名空间非常重要的一方面。它使你有能力去使用外部的包代码,像类库,不需要担心命名冲突。导入是通过 使用 use 关键字来支持的。制定一个自定义的别名 跟着 as 关键字。

use [name of class, interface or namespace] as [optional_custom_alias]

导入时怎样实现的呢  

How it's Done

一个完全限制的名称 可以取一个短一点的非限制的名称,这样你当你想用它的时候不用每次都写一个长长的完全限制的名称。别名或者导入应该发生(或者叫使用)于最高层级的作用域或者是全局空间中。 尝试在一个方法或是函数的作用域中使用导入时不合法(不和语法的)的。

<?php
namespace OtherProject; // This holds the MyProject\Database namespace with a Connection class in it
require 'myproject/database/connection.php'; // If we want to access the database connection of MyProject, we need to use its fully qualified name as we're in a different name space
$connection = new \MyProject\Database\Connection(); // Import the Connection class (it works exactly the same with interfaces)
use MyProject\Database\Connection; // Now this works too! Before the Connection class was aliased PHP would not have found an OtherProject\Connection class
$connection = new Connection(); // Import the MyProject\Database namespace
use MyProject\Database; $connection = new Database\Connection()

 或者,你可以取一个不同的名字作为别名。

<?php
namespace OtherProject; require 'myproject/database/connection.php'; use MyProject\Database\Connection as MyConnection; $connection = new MyConnection(); use MyProject\Database as MyDatabase; $connection = new MyDatabase\Connection();

你也可以允许导入全局的类,像 Exception类。当导入之后呢,你就可以再也不用写他的长长的完全限制的名称了。

注意,导入的名称不是被解析成相对于当前命名空间的路径,而是绝对路径,从全区空间开始。这意味着 前导的反斜杠付是不必要的也是不推荐的。

<?php
namespace MyProject; // Fatal error: Class 'SomeProject\Exception' not found
throw new Exception('An exception!'); // OK!
throw new \Exception('An exception!'); // Import global Exception. 'Exception' is resolved from an absolute standpoint, the leading backslash is unnecessary
use Exception; // OK!
throw new Exception('An exception!');

尽管可以动态调用命名空间的代码,  但是动态的导入是不支持的。

<?php
namespace OtherProject; $parser = 'markdown'; // This is valid PHP
require 'myproject/blog/parser/' . $parser . '.php'; // This is not
use MyProject\Blog\Parser\$parser;

结论 

命名空间是用来避免定义冲突的和引入了更多的灵活性,更好的组织你的代码的。记住你没有必要说非得使用命名空间。它的使用是结合面向对象的工作流中会常见。 然而,还是希望,你将考虑将你的PHP项目带入到下一个层次中,通过使用命名空间。你决定这样做了吗?

最新文章

  1. vue-router2.0 组件之间传参及获取动态参数
  2. Oracle之分页查询
  3. phpstorm的安装、破解、和汉化
  4. faster with MyISAM tables than with InnoDB or NDB tables
  5. CF 628C --- Bear and String Distance --- 简单贪心
  6. express 查看版本号
  7. 分布式一致性原理—CAP
  8. C#自定义事件:属性改变引发事件示例
  9. java中集合杂记
  10. django drf 开发 ~ models基础学习
  11. GDAL——命令使用专题——gdalinfo命令
  12. Kafka入门 --安装和简单实用
  13. 洛谷 P1160 队列安排
  14. 疫情控制 [NOIP2012]
  15. 和TransDecoder 学习perl 自定义模块的路径问题
  16. 成功解决android studio打包报错
  17. 开源播放器 ijkplayer (二) :ijkplayer倍速变调问题解决方案
  18. 15.unbuntu下安装vmware-tools
  19. cookie的详解
  20. Gnucash数据库结构

热门文章

  1. mapreduce框架详解
  2. ssh三大框架,三层架构 整合测试!完整分页代码,JdbcTemplate等测试,存储过程调用,留着以后复习吧
  3. 用友CDM系统,将货位间商品移库单(一步)修改为内调出入库单(一步)方法使用
  4. Android开发(25)--framebyframe帧动画并实现启动界面到主界面的跳转
  5. git shell 常用命令
  6. 微信公众号开发之网页中及时获取当前用户Openid及注意事项
  7. C语言之变量与常量的介绍
  8. Node.js学习笔记(二):模块
  9. React一些必须要知道的基础
  10. JMS(java消息服务)整合Spring项目案例