Home » Code » PHP中命名空间与自动加载

PHP中命名空间与自动加载

命名空间在面向对象的语言如Java、C#中很早就有,PHP在5.3之后也加了进来,但至今不少人写程序仍然无视之。给人最先的不爽就是怎么用个“\”右斜杠表示,人家都用点“.”非常直观方便,直接影响了使用心情。命名空间最大的作用就是防止命名冲突,一个命名空间就像一个封闭的盒子,盒子里面的内容是单独的跟外边全局的内容即名字相同也无所谓。这在多人开发的时候非常有用。看下面这个例子:

namespace a;

function ltrim($param)
{
	return "shabime<br/>";
}

echo ltrim("haha");

ltrim()是系统自带的一个全局函数,如果我们不使用命名空间,你是不能redeclare它的。有了命名空间,你就能在这个命名空间内随便定义函数、常量与类了(只有这三种数据类型受命名空间的影响),不用担心跟其他人或者系统全局发生重名问题,只要在你当前命名空间下不重名即可。

命名空间的定义只需要要文件头使用namespace+名称就可以了,定义命名空间必须在文件最顶端,也就是在定义命名空间之前不能有其他的代码。使用的时候可以将整个命名空间写完,或者使用use。下面的例子是当前文件夹有个index.php和app文件夹,run文件夹有一个run.php文件,run.php的内容如下:

namespace app;

class Run
{
	public static function run()
	{	
		echo 'app run run!<br/>';
	}
}

现在要在index.php中调用Run类的run方法,首先你得把文件引入。之后,如果你直接Run::run(),直接报找不到Run类,因这这样子系统会在当前命名空间下找Run类,index.php没有定义命名空间但它还是有一个“空间”的,肯定没找到,然后全局里面找,当然也找不到。Run类是在app命名空间下的,要访问到它并使用就必须指定命名空间,你可以这样子使用:

app\Run::run();

或者使用use:

use app\Run;
Run::run();

注意:use必须use到具体命名空间下的类名,不能只use命名空间!

这时候或许你已经注意到一个问题,如果命名空间较深我又不use直接写完不是得写好大一长串?没错,确实是这样的。先use的话不用写那么一长串了,但如果我要使用多个类,不得先一阵use,这跟之前的不用自动加载先一阵require有何区别?好吧,没错,确实是没区别。这时候可能想骂娘了,命名空间确实坑爹,怪不得没什么人用它。如果明确知道不会写重名,没必要用命名空间了吧。这时候的答案仍然是,You are right。

但是,命名空间解决了命名冲突这个在多人同时开发的大型项目中经常遇到的问题,还是很有必要的。不能只因为你项目小,就自己在鼓捣,就一味的排斥它。上边说的要写很长串,或者多次use,还可以这样子缓解一下,那就是只use到命名空间下,给这个命名空间一个别名:

//假定app文件夹很深,app命名空间下很多文件需要用到
use xxx\xxx\xxx\...\app as app;
app\Run::run();
app\Xxx::xxx();//使用app命名空间下的其他类,其他方法

这样子,是不是好多了。

有了命名空间之后,最容易出错的该是使用类的时候,这个类的寻找路径是什么样的。比如new a\b\Class.php与new \a\b\Class.php有什么区别?这个就跟相对路径与绝对路径一个道理,最开始加了”\”表示从“根”开始找这个命名空间,不加则是在当前命名空间下再找命名空间。何为“根”,对于单入口应用而言,就是入口文件所在的那个文件夹了。

有了命名空间,当new一个类找不到的时候,系统会将包括命名空间在内的类名传给自动加载函数,因此,如果命名空间跟文件路径一致,那就可以只通过“类名”找到这个文件了。php界有这么一个PSR-0规范,就是为实现通过命名空间实现自动加载做了一些规定。跟自动加载相关的关键一项就是“命名空间与绝对路径一致”,像我上边,app文件夹下的run.php的命名空间就定义为app而不是其他,就是遵循这个规范。遵循这个规范之后,在自动加载函数中只需要将类名中的”\”转换为路径分割符,就能找到文件将之引入了。

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Time limit is exhausted. Please reload CAPTCHA.