## 1. 什么是命名空间?
命名空间对应的英文是 namespace ,所以翻译成中文叫命名空间,在很多的语言中,都有这个 namespace ,那么它用来干嘛呢?说简单点就是为了避免代码命名重复。因为包括 php 在内的很多语言,是不允许 function name 或者 class name重复的,如果你同时 require 2 个 class ,如果调用的对应的 class name 是一样,系统是会报错的。所有,一般的对面对象的语言都会有 namespace ,用来避免这种情况出现。
php 在 5.3 之前是不支持 namespace 的,所以很多程序员的 class name 和 function name 经常会用 class_name_1 , class_name_2,class_name_3 用_隔开等类似这样的方式来避免类的重复,很是这样却不美观和优雅,而且维护起来比较费劲很难理解。于是 php在5.3 重磅突出了 namespace。
举个例子,先常规的写,不使用 namespace
现在我的同一个目录下 3 个 php 文件,分别是:index.php,name.php,gender.php。
三个文件很简单,就是输出一段很简单文字的代码。
name.php
~~~php
<?php
class info {
public static function get_info()
{
echo 'hello word 1';
}
}
~~~
gender.php
~~~php
<?php
class info {
public static function get_info()
{
echo 'hello word 2';
}
}
~~~
然后在index.php分别rquire这2个文件
~~~php
<?php
require './name.php';
require './gender.php';
info::get_info();
info::get_info();
~~~
name.php 和 gender.php 里的类名字是一样的,都叫 info ,或许你会反问我,你是傻逼吗?你不会给这2个类取不一样的名字啊。因为这里只是小测试小项目,你当然会取不一样的名字。但是比如你用 composer 导入其他人的开源库的代码,肯定是会有 class name 是一样的,这一点是毋庸置疑的,所以你还是无法避免这个问题的。
这时候,你运行下 index.php 就直接报致命错误了的,说类重新声明了。
~~~php
Fatal error: Cannot redeclare class info in D:\wamp\www\testphp\namespace\gender.php on line 3
~~~
下面再简单说下如何用 namespace 避免重复,还是这个例子,下面会着重讲。
我们加入 namespace 看下:
name.php
~~~php
<?php
namespace Foo;
class info {
public static function get_info()
{
echo 'hello word 1';
}
}
~~~
gender.php
~~~php
<?php
namespace Fee;
class info {
public static function get_info()
{
echo 'hello word 2';
}
}
~~~
然后在 index.php 分别 rquire 这 2 个文件,并用 namespace 的方式调用。
~~~php
<?php
require './name.php';
require './gender.php';
Foo\info::get_info();
Fee\info::get_info();
~~~
我们刷新下 index.php , 看看结果是啥,看,输出的就是我们想要的结果,没有报错:
~~~php
hello word 1hello word 2
~~~
function name 也是不能重复的,这里就不举例了,原理是一样的。
## 2. 为什么目前国内使用率不高?
截止到目前为止,老实话其实我也没接触过任何关于php的命名空间的项目或者代码,我现在仔细想想为什么会这样呢。大概或许是这几点吧:
目前国内的php版本已经处于 5.3* , 而且还有很多处于 5.2 , php 的命名空间的更新是在 5.3 版本上加入的,所以使用率不是很高。
貌似目前的国内的开源的项目或者框架基本没用 namespace ,或许也有这个因素的影响吧,大家开发写代码想到的就是如何运用好 MVC 和面向对象,想起用 namespace 的少之又少。
namespace 对比 PHP 中的其他语法还是有点羞涩难懂的,而且一些很诡异的书写方式和命名方式,这或许也是一个比较大的影响因素,再加上平时项目中使用率不高,基本上也就不会用它了
## 3. 在 PHP类文件中使用namespace
下面我们进入正题,真正意义上来学一下php中的命名空间。php的命名空间其实还是非常简单的。
如何声明一个 namespace
前面一个例子呢,简单的说了一下如何声明,现在着重说一下,先提前说明下,稍显变态。
像这样子申明:
~~~php
namespce name
~~~
先看个例子:
~~~php
<?php
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
~~~
必须用关键字 namespace 来做声明,后面加上命名空间的名字。这个关键字一行必须写在一个 php 文件的最开头,前面不能有任何的语句,额,这一点是有点变态哈,但是也还能忍受。所以,包括 ```ehco 222;, $info = array()``` 等这一系列的语句的都不能写在 namespace 前面。不然就会报致命错误:
~~~php
Fatal error: Namespace declaration statement has to be the very first statement in the script in D:\wamp\www\testphp\namespace\gender.php on line 3
~~~
所以以下几个是错误的,会报错:
~~~php
<?php
$info = array();
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
<?php
echo 345;
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
<?php
header("Content-type: text/html; charset=utf-8");
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
~~~
还有最重要的一个容易忽略的就是 `<?php`,这个声明是 php 的文件的标记也必须得定格写,前面不能有空格, 不然也会报错。这一点非常重要,极其容易忽略,就产生错误了。
`<?php` 前面有空格,也会报错。
`<?php` //前面有个空格,也会报错
~~~php
namespace FOO
class info
{
public function test()
{
echo 'HELLO WORD!';
}
}
~~~
一个 namespace 的 name 的书写方式
上面的几个例子中,我们取的命名空间的 name 叫 Foo 和 Fee ,当然这只是一个例子,我们在取名字的时候必须得是有意义的。按照 PSR-0 的规范要求呢,这个名字必须得有一个上级的 Vendor Name ,可以理解为你的项目文件夹的名字,这样的目的呢,第一是为了防止 namespace 的 name 也重复,第二是为了更好的定位文件的位置。也许有点看不懂,举个例子:
假如 gender.php 和 name.php 文件中的 class name 都取名为 :info , 那么必须要设置 2 级的 namespace。
gender.php
~~~php
<?php
namespace App\Fee;
class info {
public static function get_info()
{
echo 'hello word 2';
}
}
~~~
name.php
~~~php
<?php
namespace App\Foo;
class info {
public static function get_info()
{
echo 'hello word 1';
}
}
~~~
namespace 的名字叫 App\Foo 和 App\Fee, App 就是 Vendor name 也就是项目的目录。这样就很好的区分了。
如果,name.php 和 gender.php 中的 class name 不一样,也就不会重复了,理论上可以不用命名空间,但是现在用命名空间不仅仅是为了防止重复,现在同样也是为了定位这个文件的目录,为了好快速找到。所以,就只需一层 Vendor name 就可以了:
gender.php
~~~php
<?php
namespace App;
class gender {
public static function get_info()
{
echo 'hello word 2';
}
}
~~~
name.php
~~~php
<?php
namespace App;
class name {
public static function get_info()
{
echo 'hello word 1';
}
}
~~~
上面的我们都将它们命名空间为 APP ,因为它们的 class name 不一样,所以组成的访问类的方式: APP\gender::get_info(); 和 App\name::get_info(); 也就不一样。也就不存在重复的关系。我们在下面将如何访问一个 namespace 时会继续讲到。
name 命名规范 和 php 中变量的命名规则一样,什么首字母不能是数字啊。只能有数字,字母,下划线_组成,也不能是系统保留关键字等。( \ 这个符号可以用的,因为是在 namespace 中用来分割目录的)
namespace 的访问
上面我用了大幅篇章来声明如何定义一个 namespace ,当然还有一些很诡异的申明方式,我们放到后面起说。现在来说,如何访问一个 namespace。
访问一个 namespace 其实和访问一个 class 类一模一样,先是导入 class ,再是 new 适用等。
### 第 1 种方式
像这样子访问调用:
~~~php
Vendor\namespce\class
gender.php
<?php
namespace App;
class gender {
//静态方法,可以直接用::访问
public static function get_info()
{
echo 'hello word 2';
}
}
name.php
<?php
namespace App;
class name {
public function get_info()
{
echo 'hello word 1';
}
}
<?php
require './gender.php';
require './name.php';
//static function 直接使用
App\gender::get_info();
//一般方式,先new,再调用
$name = new App\name;
$name->get_info();
~~~
和调用普通的类一样,先 require 进来,只不过现在的类名变成了:在 class name 前面多加了一个 namespace name 并用\ 隔开,如果是静态方法就直接 ::function name 调用就可以了。如果是常规方法就先 new 再调用 function name。
### 第 2 中方式:使用 use 关键字
用过其他语言中的 namespace 的或许知道有一个关键字 use 来到导入命名空间的,php 中也是可以的。我们试一下:
像这样子访问调用:
~~~php
use Vendor\namespce\class
class::function
index.php
<?php
require './gender.php';
require './name.php';
//第1种 use 用来导入gender类
use App\gender;
gender::get_info();
use App\name;
$name_object = new name;
$name_object->get_info();
//第2种 use ** as alise_name 取别名
use App\gender as alise_gender;
alise_gender::get_info();
use App\name as alise_name;
$alise_name_object = new alise_name;
$alise_name_object->get_info();
~~~
第 1 中是用 use 用来导入的,导入了 App\gender 类,然后就可以直接调用 gender:: 静态方法或者 new name 再来调用普通方法。
第 2 种是用 use as alise_name 方法取了一个别名而已,用法和第一种类似一致。
我是推荐用第 1 种的,直接使用 use 导入就好了。用 as 别名反而容易造成错误和复杂度,而且你使用 use 的方式,已经是将 namespace 给省略掉了,变成正常的 class 调用方式。一般 as 用在 namespace 申明 function 时候用,在下面会讲到。
OK. php 使用 命名空间基本的东西已经说完了。平时如果使用 namespace ,也就上面这些东西了。所以如果掌握了,基本也就没问题了。
但是,我们因为是在学习它,所以还是要继续深挖一些 namespace 其他的知识点的。在下面接着说。
## 4. 在php function文件中使用namespace
大多数适用 namespace 其实是在类文件( class )中使用的,在 function 文件中也是可以使用的,也能够防止重复。但是用的很少,使用起来也很蛋疼。
还是看例子:
有一个 height.php 文件,用 namespace 申明一个命名空间 App
~~~php
<?php
namespace App;
function test()
{
echo ' this is a namespace function test';
}
~~~
然后在 index.php 中 require 并引用这个 namespace App
~~~php
<?php
require './height.php';
//第一种方式调用,和之前一样
App\test();
//第二种方式调用,使用use, 必须配合as 使用,不然报错
use App;
test(); //报错
//正确的使用方式
use App as anthorApp;
anthorApp\test();
~~~
上面一个报错的使用是我们自己想当然,想着没有 class name 了,是不是就可以直接使用 function name 了,结果就报错了。因为不管使用好是不使用 use,当得像这样子访问 class\function 。所以,既然 function 没有 class ,那么我们就可以使用 use namespace as class 生成一个别名 anthorApp,再用这个 anthorApp\test() 就可以访问了。
所以,你看到的这篇文件中这一处是错误的:PHP V5.3 中的新特性,第 3 部分: 名称空间 :
~~~php
/* File3.php */
<?php
include './Foo.php';
use Foo;
bar(); // outputs "calling bar...."; //这种方式是错的。
?>
~~~
所以总结下: 如果我们用 namespace 声明 function 文件时,最好直接使用 App\test() 调用吧,如果想用 use 关键字,必须要用 as 一个别名。
## 5. 在php中混合使用各种
什么叫混合使用呢。就是既使用 namespace 声明 class,又声明 function,又单独使用,虽然有点变态,但是为了学习它,为了找到 namespace 的精髓,我也是蛮拼的。
直接上代码吧:
height.php 文件中,用 namespace 同时声明的 function 和 class
~~~php
<?php
namespace App;
function test()
{
echo ' this is a namespace function test';
}
class height
{
public static function test()
{
echo 'hello word 3';
}
}
~~~
在 function.php 写的是正常普通的 function 和 class
~~~php
<?php
function test()
{
echo ' this is a function test';
}
class height {
public static function test()
{
echo 'hello word 4';
}
}
~~~
好。那么这么变态的东西,如何访问呢。仔细想想上面说的那么多的,其实很快就可以写出来,而且不会报错:
index.php
~~~php
<?php
require './height.php';
require './function.php';
// 调用namespace的function 和 class 直接调
App\test();
App\height::test();
//调用namespace的function 和 class 使用use
use App as anthorApp;
anthorApp\test();
use App\height;
height::test();
use App\height as anthorClssApp;
anthorClssApp::test();
//调用普通的
test();
height::test();
~~~
案例参考:
https://www.zybuluo.com/phper/note/65479
http://www.ibm.com/developerworks/cn/opensource/os-php-5.3new3/
http://www.cnblogs.com/thinksasa/p/3423480.html
http://www.w3cschool.cc/php/php-namespace.html