您的位置:首页 > 编程语言 > PHP开发

关于Thinkphp3.2 命名空间的说明-php5.3命名空间介绍-TP自动加载

2017-05-02 14:18 686 查看


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文件中可以存在多个命名空间,第一个命名空间前不能有任何代码。内容空间声明后的代码便属于这个命名空间,例如:
<?php
echo 111;       //由于namespace前有代码而报错
namespace Teacher;
class Person{
function __construct(){
echo 'Please study!';
}
}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8

2.调用不同空间内类或方法需写明命名空间。例如:
<?php
namespace Teacher;
class Person{
function __construct(){
echo 'Please study!<br/>';
}
}
function Person(){
return 'You must stay here!';
};
namespace Student;
class Person{
function __construct(){
echo 'I want to play!<br/>';
}
}
new Person();                    //本空间(Student空间)
new \Teacher\Person();           //Teacher空间
new \Student\Person();           //Student空间
echo \Teacher\Person();          //Teacher空间下Person函数
//输出:
I want to play!
Please study!
I want to play!
You must stay here!
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文件:
<?php     //1.php
class Person{
function __construct(){
echo 'I am one!<br/>';
}
}
1
2
3
4
5
6
1
2
3
4
5
6
<?php
namespace Newer;
require_once './1.php';
new Person();      //报错,找不到Person;
new \Person();     //输出 I am tow!;
1
2
3
4
5
1
2
3
4
5
<?php     //2.php
namespace Two
class Person{
function __construct(){
echo 'I am tow!<br/>';
}
}
1
2
3
4
5
6
7
1
2
3
4
5
6
7
<?php
namespace New;
require_once './2.php';
new Person();      //报错,(当前空间)找不到Person;
new \Person();     //报错,(公共空间)找不到Person;
new \Two\Person();  //输出 I am tow!;
1
2
3
4
5
6
1
2
3
4
5
6

4.下面我们来看use的使用方法:(use以后引用可简写)
namespace School\Parents;
class Man{
function __construct(){
echo 'Listen to teachers!<br/>';
}
}
namespace School\Teacher;
class Person{
function __construct(){
echo 'Please study!<br/>';
}
}
namespace School\Student;
class Person{
function __construct(){
echo 'I want to play!<br/>';
}
}
new Person();                   //输出I want to play!
new \School\Teacher\Person();   //输出Please study!
new Teacher\Person();           //报错
----------
use School\Teacher;
new Teacher\Person();           //输出Please study!
----------
use School\Teacher as Tc;
new Tc\Person();           //输出Please study!
----------
use \School\Teacher\Person;
new Person();           //报错
----------
use \School\Parent\Man;
new Man();           //报错
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');
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: