最近学习一下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项目带入到下一个层次中,通过使用命名空间。你决定这样做了吗?

Namespacing in PHP (php 中使用命名空间)的更多相关文章

  1. C语言中的命名空间

    C语言中的命名空间 命名空间是为了解决 "在相同作用域内如何区分 相同的标识符". 说明: ①只有在相同作用域的情况下才能使用到命名空间去区分标识符,在嵌套的作用域.不同的作用域区 ...

  2. 替换 wcf 消息传输中的 命名空间

    替换 wcf 消息传输中的 命名空间,http://vanacosmin.ro/Articles/Read/WCFEnvelopeNamespacePrefix

  3. JavaScript中创建命名空间

    引用:http://ourjs.com/detail/538d8d024929582e6200000c   在JavaScript中全局变量经常会引起命名冲突,甚至有时侯重写变量也不是按照你想像中的顺 ...

  4. 在JavaScript中创建命名空间的几种写法

    在JavaScript中全局变量经常会引起命名冲突,甚至有时侯重写变量也不是按照你想像中的顺序来的,可以看看下面的例子: var sayHello = function() { return 'Hel ...

  5. js中创建命名空间的几种写法

    在JavaScript中全局变量经常会引起命名冲突,甚至有时侯重写变量也不是按照你想像中的顺序来的,可以看看下面的例子: var sayHello = function() { return 'Hel ...

  6. Entity Framework中实体模型命名空间的问题

    在添加一个实体数据模型的时候(就是扩展名为edmx那位)属性里明明设置了自己的命名空间,但是后台的Designer.cs命名空间生成规则却是项目的默认命名空间加edmx文件所在文件夹的名称, 是BUG ...

  7. 解读Python编程中的命名空间与作用域

    变量是拥有匹配对象的名字(标识符).命名空间是一个包含了变量名称们(键)和它们各自相应的对象们(值)的字典.一个Python表达式可以访问局部命名空间和全局命名空间里的变量.如果一个局部变量和一个全局 ...

  8. 说说PHP中的命名空间相关概念

    说说PHP中的命名空间相关概念 1. PHP中的命名空间是什么? 什么是命名空间?"从广义上来说,命名空间是一种封装事物的方法.在非常多地方都能够见到这样的抽象概念. 比如.在操作系统中文件 ...

  9. PHP中的命名空间(namespace)及其使用详解

    PHP中的命名空间(namespace)及其使用详解 晶晶 2年前 (2014-01-02) 8495次浏览 PHP php自5.3.0开始,引入了一个namespace关键字以及__NAMESPAC ...

随机推荐

  1. 我的TDD实践---UnitTest单元测试

    我的TDD实践---UnitTest单元测试 “我的TDD实践”系列之UnitTest单元测试 写在前面: 我的TDD实践这几篇文章主要是围绕测试驱动开发所展开的,其中涵盖了一小部分测试理论,更多的则 ...

  2. make deb for debian/ubuntu, package software for debian/ubuntu

    here you may find useful information: =====================X8---------------------------------8X==== ...

  3. mpi和cuda混合编程的正确编译

    针对大数据的计算,很多程序通过搭建mpi集群进行加速,并取得了很好的效果.算法内部的加速,当前的并行化趋势是利用GPU显卡进行算法加速.针对并行性非常好的算法,GPU加速效果将远大于集群带来的加速效果 ...

  4. Facebook开源的基于SQL的操作系统检测和监控框架:osquery

    osquery简介 osquery是一款由facebook开源的,面向OSX和Linux的操作系统检测框架. osquery顾名思义,就是query os,允许通过使用SQL的方式来获取操作系统的数据 ...

  5. 没有花括号(大括号)的for循环也能正确执行

    代码一 for循环没有{}大括号(花括号),在for语句下面是一条语句. for(var i=0;i<3;i++) console.log(1,i); 上面的代码能无误输出: 1 01 11 2 ...

  6. jsp-3 简单的servlet连接mysql数据库 使用mvc的登录注册

    简单的servlet连接mysql数据库 使用mvc的登录注册 commons-dbutils-1.6 mysql-connector-java-5.1.40-bin c3p0-0.9.5.2 mch ...

  7. Josephus问题的不同实现方法与总结

    /************************************************************************/ /* Josephus问题--数组实现 */ /* ...

  8. 仿qq的侧拉菜单效果

    自定义控件 import android.animation.ArgbEvaluator; import android.animation.FloatEvaluator; import androi ...

  9. nordic DFU固件升级

    一:测试固件芯片类型: nordic 52832 二:下载升级源码 1>nRF Toolbox App 源码  https://github.com/NordicSemiconductor/IO ...

  10. Spark-GraphxAPI学习笔记

    图的集合视图 graph包含三个基本的类集合视图: val vertices: VertexRDD[VD] val edges: EdgeRDD[ED] val triplets: RDD[EdgeT ...