Thinkphp3.2命名空间
3.2版本全面采用命名空间方式定义和加载类库文件,有效的解决多个模块之间的冲突问题,并且实现了更加高效的类库自动加载机制。
命名空间的概念必须了解,否则会成为3.2版本开发的重大障碍。
如果不清楚什么是命名空间,可以参考PHP手册:PHP命名空间
由于新版完全采用了命名空间的特性,因此只需要给类库正确定义所在的命名空间,而命名空间的路径与类库文件的目录一致,那么就可以实现类的自动加载。 例如,Org\Util\File
类的定义为:
namespace Org\Util;
class File {
}
其所在的路径是 ThinkPHP/Library/Org/Util/File.class.php
,因此,如果我们实例化该类的话:
$class = new \Org\Util\File();
系统会自动加载 ThinkPHP/Library/Org/Util/File.class.php
文件。
注意:和3.1不同,我们无需在实例化命名空间定义的类之前导入类库文件了。
根命名空间
根命名空间是一个关键的概念,以上面的Org\Util\File
类为例,Org
就是一个根命名空间,其对应的初始命名空间目录就是系统的类库目录(ThinkPHP/Library
),Library目录下面的子目录会自动识别为根命名空间,这些命名空间无需注册即可使用。
例如,我们在Library目录下面新增一个My根命名空间目录,然后定义一个Test类如下:
namespace My;
class Test {
public function sayHello(){
echo 'hello';
}
}
Test类保存在 ThinkPHP/Library/My/Test.class.php
,我们就可以直接实例化和调用:
$Test = new \My\Test();
$Test->sayHello();
模块中的类库命名空间的根都是以模块名命名,例如:
namespace Home\Model;
class UserModel extends \Think\Model {
}
其类文件位于 Application/Home/Model/UserModel.class.php
。
namespace Admin\Event;
class UserEvent {
}
其类文件位于 Application/Admin/Event/UserEvent.class.php
。
3.2.1版本以上的话,允许设置对应用类库不使用命名空间,你在配置文件中进行如下设置:
'APP_USE_NAMESPACE' => false,
那么,所有的应用类库不再需要使用命名空间定义,但继承和调用核心类和系统类的时候,仍然需要使用命名空间,例如:
class UserModel extends \Think\Model {
}
特别注意:如果你需要在3.2版本中实例化PHP内置的类库或者第三方的没有使用命名空间定义的类,需要采用下面的方式:
$class = new \stdClass();
$sxml = new \SimpleXmlElement($xmlstr);
PHP5.3 命名空间介绍:
在PHP中,出现同名函数或是同名类是不被允许的。为防止编程人员在项目中定义的类名或函数名出现重复冲突,在PHP5.3中引入了命名空间这一概念。
1.命名空间,即将代码划分成不同空间,不同空间的类名相互独立,互不冲突。一个php文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。内容空间声明后的代码便属于这个命名空间,例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
2.调用不同空间内类或方法需写明命名空间。例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
3.在命名空间内引入其他文件不会属于本命名空间,而属于公共空间或是文件中本身定义的命名空间。例:
首先定义一个1.php和2.php文件:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
4.下面我们来看use的使用方法:(use以后引用可简写)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
ThinkPHP3.2 自动加载
在3.2中,基本上无需手动加载类库文件,你可以很方便的完成自动加载。
命名空间自动加载
系统可以通过类的命名空间自动定位到类库文件,例如:
我们定义了一个类 Org\Util\Auth
类:
namespace Org\Util;
class Auth {
}
保存到 ThinkPHP/Library/Org/Util/Auth.class.php
。
接下来,我们就可以直接实例化了。
new \Org\Util\Auth();
在实例化Org\Util\Auth
类的时候,系统会自动加载 ThinkPHP/Library/Org/Util/Auth.class.php
文件。
框架的Library目录下面的命名空间都可以自动识别和定位,例如:
├─Library 框架类库目录
│ ├─Think 核心Think类库包目录
│ ├─Org Org类库包目录
│ ├─ ... 更多类库目录
Library目录下面的子目录都是一个根命名空间,也就是说以Think、Org为根命名空间的类都可以自动加载:
new Think\Cache\Driver\File();
new Org\Util\Auth();
new Org\Io\File();
都可以自动加载对应的类库文件。
你可以在Library目录下面任意增加新的目录,就会自动注册成为一个新的根命名空间。
注册新的命名空间
除了Library目录下面的命名空间之外,我们还可以注册其他的根命名空间,例如:
'AUTOLOAD_NAMESPACE' => array(
'My' => THINK_PATH.'My',
'One' => THINK_PATH.'One',
)
配置了上面的AUTOLOAD_NAMESPACE
后,如果我们实例化下面的类库
new My\Net\IpLocation();
new One\Util\Log();
会自动加载对应的类库文件
ThinkPHP/My/Net/IpLocation.class.php
ThinkPHP/One/Util/Log.class.php
如果命名空间不在Library目录下面,并且没有定义对应的AUTOLOAD_NAMESPACE
参数的话,则会当作模块的命名空间进行自动加载,例如:
new Home\Model\UserModel();
new Home\Event\UserEvent();
由于ThinkPHP/Library目录下面不存在Home目录,也没在AUTOLOAD_NAMESPACE
参数定义Home命名空间,所以就把Home当成模块命名空间来识别,所以会自动加载:
Application/Home/Model/UserModel.class.php
Application/Home/Event/UserEvent.class.php
注意:命名空间的大小写需要和目录名的大小写对应,否则可能会自动加载失败。
类库映射
遵循我们上面的命名空间定义规范的话,基本上可以完成类库的自动加载了,但是如果定义了较多的命名空间的话,效率会有所下降,所以,我们可以给常用的类库定义类库映射。命名类库映射相当于给类文件定义了一个别名,效率会比命名空间定位更高效,例如:
Think\Think::addMap('Think\Log',THINK_PATH.'Think\Log.php');
Think\Think::addMap('Org\Util\Array',THINK_PATH.'Org\Util\Array.php');
也可以利用addMap方法批量导入类库映射定义,例如:
$map = array('Think\Log'=>THINK_PATH.'Think\Log.php','Org\Util\Array'=>THINK_PATH.'Org\Util\Array.php');
Think\Think::addMap($map);
当然,比较方便的方式是我们可以在模块配置目录下面创建alias.php文件用于定义类库映射,该文件会自动加载,定义方式如下:
return array(
'Think\Log' => THINK_PATH.'Think\Log.php',
'Org\Util\Array' => THINK_PATH.'Org\Util\Array.php'
);
自动加载的优先级
在实际的应用类库加载过程中,往往会涉及到自动加载的优先级问题,以Test\MyClass
类为例,自动加载的优先顺序如下:
- 判断是否有注册了Test\MyClass类库映射,如果有则自动加载类库映射定义的文件;
- 判断是否存在Library/Test目录,有则以该目录为初始目录加载;
- 判断是否有注册Test根命名空间,有则以注册的目录为初始目录加载;
- 如果以上都不成立,则以Test为模块目录进行初始目录加载;
以上面获取到的初始目录加载命名空间对应路径的文件;
手动加载第三方类库
如果要加载第三方类库,包括不符合命名规范和后缀的类库,以及没有使用命名空间或者命名空间和路径不一致的类库,或者你就是想手动加载类库文件,我们都可以通过手动导入的方式加载。
我们可以使用import方法导入任何类库,用法如下:
// 导入Org类库包 Library/Org/Util/Date.class.php类库
import("Org.Util.Date");
// 导入Home模块下面的 Application/Home/Util/UserUtil.class.php类库
import("Home.Util.UserUtil");
// 导入当前模块下面的类库
import("@.Util.Array");
// 导入Vendor类库包 Library/Vendor/Zend/Server.class.php
import('Vendor.Zend.Server');
对于import方法,系统会自动识别导入类库文件的位置,ThinkPHP可以自动识别的类库包包括Think、Org、Com、Behavior和Vendor包,以及Library目录下面的子目录,如果你在Library目录下面创建了一个Test子目录,并且创建了一个UserTest.class.php类库,那么可以这样导入:
import('Test.UserTest');
其他的就认为是应用类库导入。
注意,如果你的类库没有使用命名空间定义的话,实例化的时候需要加上根命名空间,例如:
import('Test.UserTest');
$test = new \UserTest();
按照系统的规则,import方法是无法导入具有点号的类库文件的,因为点号会直接转化成斜线,例如我们定义了一个名称为User.Info.class.php 的文件的话,采用:
import("Org.User.Info");
方式加载的话就会出现错误,导致加载的文件不是Org/User.Info.class.php 文件,而是Org/User/Info.class.php 文件,这种情况下,我们可以使用:
import("Org.User#Info");
来导入。
大多数情况下,import方法都能够自动识别导入类库文件的位置,如果是特殊情况的导入,需要指定import方法的第二个参数作为起始导入路径。例如,要导入当前文件所在目录下面的 RBAC/AccessDecisionManager.class.php 文件,可以使用:
import("RBAC.AccessDecisionManager",dirname(__FILE__));
如果你要导入的类库文件名的后缀不是class.php而是php,那么可以使用import方法的第三个参数指定后缀:
import("RBAC.AccessDecisionManager",dirname(__FILE__),".php");
注意:在Unix或者Linux主机下面是区别大小写的,所以在使用import方法的时候要注意目录名和类库名称的大小写,否则会导入失败。
如果你的第三方类库都放在Vendor目录下面,并且都以.php为类文件后缀,也没用采用命名空间的话,那么可以使用系统内置的Vendor函数简化导入。 例如,我们把 Zend 的 Filter\Dir.php 放到 Vendor 目录下面,这个时候 Dir 文件的路径就是 Vendor\Zend\Filter\Dir.php,我们使用vendor 方法导入只需要使用:
Vendor('Zend.Filter.Dir');
就可以导入Dir类库了。
Vendor方法也可以支持和import方法一样的基础路径和文件名后缀参数,例如:
Vendor('Zend.Filter.Dir',dirname(__FILE__),'.class.php');