slan's blog

Loneliness or short time relief?

php利用命名空间管理项目模块

2013-06-09 19:40:00 +0000 UTC

php利用命名空间管理项目模块

缘由

之前Tita的model结构是这样的,model目录用自动加载机制来加载用到的类,运行久了就有一个问题,这一个目录的类越来越多,很不好管理,于是就想分目录来存放相关的类,将不同类别的类文件放到不同的目录只有,自动加载越来越不好弄了,因为要遍历model下的所有目录。如果子目录还要划分小类,那更是一场灾难,于是将目光转向命名空间,虽然觉得反斜杠来当分隔符比较的2,但是相对管理那么多复杂的类,还是很激动的将命名空间支持添加到了Tita。

在这里,我们利用命名空间和php自动加载机制,较为完美的实现了模块的清晰划分,目前对效果很满意。看反斜杠也不觉得反感了。

教程

如何理解命名空间,在命名空间出现以前,所有的函数,类变量都在一个空间。命名空间出来以后,这块空间就叫做了一个特殊的全局空间,对于没有划分自己空间的代码,都放在全局空间。

如果你新建一个空间,比如叫做admin,你就能通过new admin\User();语句来实例一个user类。如果你需要另一个全局的User类,你可以之前的老方法用new User()来创建,需要注意的是,在一个命名空间内不能不带命名空间前缀去访问另外一个空间的类,即使访问全局的类也不行。

你在admin空间内,如果要使用全局的User,则需要这样来创建:new User();带上全局空间的符号。这样我们就能根据不同的模块,来划分不同的功能了。

如何定义一个命名空间

很简单,在文件最开始的地方写上,namespace xxx;那么这个文件的内容,就都被放在了xxx空间下。如果要定义xxx的子空间,则可以写上namespace xxx\abc;

在代码中使用别名

定义好的命名空间,可以使用完全的地址去访问,比如space\child_space\mid_space\class(),但是每次用这么一长条来表示类不是太麻烦了。一个还好,当一个文件中多次使用这个空间的时候,那就相当难受了。

  • 导入命名空间,跟c++差不多。use space\child_space\mid_space;跟c++不一样的是,你导入了这个空间之后,不能直接去调用这个空间的类class(),php只能将最后的空间名当作别名来导入,在这里我们来使用mid_space\class();
  • 导入空间使用自定义别名,use space\child_space\mid_space as myspace;然后可以调用myspace\class();
  • 导入类,跟导入空间差不多,use space\child_space\mid_space\class;不过类被导入了之后,可以直接使用。调用class();也可以 use space\child_space\mid_space\class as myclass;来用一个新类名来调用。例如myclass();

如何方便的管理命名空间

如果定义了命名空间,还把文件放在一个目录,那就没多大意义了,我们可以将命名空间与目录绑定到一起。让空间与目录层次上保存一直,在Tita框架中,model是数据层目录,我们新建了一个pack目录,里面放了两个包,money和props。如图:props里面有个文件,叫做Cars.php,里面放了一个类叫Cars,声明命名空间 namespace pack\props;,我们在外部调用的时候,就可以使用pack\props\Cars()。

如何自动加载命名空间中的类

命名空间不会自动去包含相应的文件,我们使用的时候,依然需要去手动,或者自动去加载相应的文件,在之前是通过autoload或者spl_autoload_register来自动加载对应的类,其实命名空间同样能用这两个机制来加载,当你访问new pack\props\Cars();的时候,传递到autoload函数的类名将是 pack\props\Cars,我们根据自己定义的目录规则,来加载这个文件

$class=str_replace('', '/', $class);
$file=APP_PATH.'/model/'.$class.'.php';
if(is_file($file))
{
    include $file;
}

代码解释下,先将pack\props\Cars,拼成APP_PATH./model/pack/props/Cars.php 然后去包含。这样我们就自动加载了命名空间中的类。