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

来源:互联网 发布:好一点淘宝男装店铺 编辑:程序博客网 时间:2024/06/05 10:06

Thinkphp3.2命名空间

3.2版本全面采用命名空间方式定义和加载类库文件,有效的解决多个模块之间的冲突问题,并且实现了更加高效的类库自动加载机制。

命名空间的概念必须了解,否则会成为3.2版本开发的重大障碍。
如果不清楚什么是命名空间,可以参考PHP手册:PHP命名空间

由于新版完全采用了命名空间的特性,因此只需要给类库正确定义所在的命名空间,而命名空间的路径与类库文件的目录一致,那么就可以实现类的自动加载。 例如,Org\Util\File类的定义为:

  1. namespace Org\Util;
  2. class File {
  3. }

其所在的路径是 ThinkPHP/Library/Org/Util/File.class.php,因此,如果我们实例化该类的话:

  1. $class = new \Org\Util\File();

系统会自动加载 ThinkPHP/Library/Org/Util/File.class.php 文件。

注意:和3.1不同,我们无需在实例化命名空间定义的类之前导入类库文件了。

根命名空间

根命名空间是一个关键的概念,以上面的Org\Util\File类为例,Org就是一个根命名空间,其对应的初始命名空间目录就是系统的类库目录(ThinkPHP/Library),Library目录下面的子目录会自动识别为根命名空间,这些命名空间无需注册即可使用。

例如,我们在Library目录下面新增一个My根命名空间目录,然后定义一个Test类如下:

  1. namespace My;
  2. class Test {
  3. public function sayHello(){
  4. echo 'hello';
  5. }
  6. }

Test类保存在 ThinkPHP/Library/My/Test.class.php,我们就可以直接实例化和调用:

  1. $Test = new \My\Test();
  2. $Test->sayHello();

模块中的类库命名空间的根都是以模块名命名,例如:

  1. namespace Home\Model;
  2. class UserModel extends \Think\Model {
  3. }

其类文件位于 Application/Home/Model/UserModel.class.php

  1. namespace Admin\Event;
  2. class UserEvent {
  3. }

其类文件位于 Application/Admin/Event/UserEvent.class.php

3.2.1版本以上的话,允许设置对应用类库不使用命名空间,你在配置文件中进行如下设置:

  1. 'APP_USE_NAMESPACE' => false,

那么,所有的应用类库不再需要使用命名空间定义,但继承和调用核心类和系统类的时候,仍然需要使用命名空间,例如:

  1. class UserModel extends \Think\Model {
  2. }
复制代码

特别注意:如果你需要在3.2版本中实例化PHP内置的类库或者第三方的没有使用命名空间定义的类,需要采用下面的方式:

  1. $class = new \stdClass();
  2. $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.phpclass Person{    function __construct(){            echo 'I am one!<br/>';        }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
<?phpnamespace 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.phpnamespace Twoclass Person{    function __construct(){            echo 'I am tow!<br/>';        }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
<?phpnamespace 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 类:

  1. namespace Org\Util;
  2. class Auth {
  3. }

保存到 ThinkPHP/Library/Org/Util/Auth.class.php

接下来,我们就可以直接实例化了。

  1. new \Org\Util\Auth();

在实例化Org\Util\Auth类的时候,系统会自动加载 ThinkPHP/Library/Org/Util/Auth.class.php 文件。

框架的Library目录下面的命名空间都可以自动识别和定位,例如:

  1. ├─Library 框架类库目录
  2. ├─Think 核心Think类库包目录
  3. ├─Org Org类库包目录
  4. ├─ ... 更多类库目录

Library目录下面的子目录都是一个根命名空间,也就是说以Think、Org为根命名空间的类都可以自动加载:

  1. new Think\Cache\Driver\File();
  2. new Org\Util\Auth();
  3. new Org\Io\File();

都可以自动加载对应的类库文件。

你可以在Library目录下面任意增加新的目录,就会自动注册成为一个新的根命名空间。

注册新的命名空间

除了Library目录下面的命名空间之外,我们还可以注册其他的根命名空间,例如:

  1. 'AUTOLOAD_NAMESPACE' => array(
  2. 'My' => THINK_PATH.'My',
  3. 'One' => THINK_PATH.'One',
  4. )

配置了上面的AUTOLOAD_NAMESPACE后,如果我们实例化下面的类库

  1. new My\Net\IpLocation();
  2. new One\Util\Log();

会自动加载对应的类库文件

  1. ThinkPHP/My/Net/IpLocation.class.php
  2. ThinkPHP/One/Util/Log.class.php

如果命名空间不在Library目录下面,并且没有定义对应的AUTOLOAD_NAMESPACE参数的话,则会当作模块的命名空间进行自动加载,例如:

  1. new Home\Model\UserModel();
  2. new Home\Event\UserEvent();

由于ThinkPHP/Library目录下面不存在Home目录,也没在AUTOLOAD_NAMESPACE参数定义Home命名空间,所以就把Home当成模块命名空间来识别,所以会自动加载:

  1. Application/Home/Model/UserModel.class.php
  2. Application/Home/Event/UserEvent.class.php

注意:命名空间的大小写需要和目录名的大小写对应,否则可能会自动加载失败。

类库映射

遵循我们上面的命名空间定义规范的话,基本上可以完成类库的自动加载了,但是如果定义了较多的命名空间的话,效率会有所下降,所以,我们可以给常用的类库定义类库映射。命名类库映射相当于给类文件定义了一个别名,效率会比命名空间定位更高效,例如:

  1. Think\Think::addMap('Think\Log',THINK_PATH.'Think\Log.php');
  2. Think\Think::addMap('Org\Util\Array',THINK_PATH.'Org\Util\Array.php');

也可以利用addMap方法批量导入类库映射定义,例如:

  1. $map = array('Think\Log'=>THINK_PATH.'Think\Log.php','Org\Util\Array'=>THINK_PATH.'Org\Util\Array.php');
  2. Think\Think::addMap($map);

当然,比较方便的方式是我们可以在模块配置目录下面创建alias.php文件用于定义类库映射,该文件会自动加载,定义方式如下:

  1. return array(
  2. 'Think\Log' => THINK_PATH.'Think\Log.php',
  3. 'Org\Util\Array' => THINK_PATH.'Org\Util\Array.php'
  4. );

自动加载的优先级

在实际的应用类库加载过程中,往往会涉及到自动加载的优先级问题,以Test\MyClass类为例,自动加载的优先顺序如下:

  1. 判断是否有注册了Test\MyClass类库映射,如果有则自动加载类库映射定义的文件;
  2. 判断是否存在Library/Test目录,有则以该目录为初始目录加载;
  3. 判断是否有注册Test根命名空间,有则以注册的目录为初始目录加载;
  4. 如果以上都不成立,则以Test为模块目录进行初始目录加载;

以上面获取到的初始目录加载命名空间对应路径的文件;

手动加载第三方类库

如果要加载第三方类库,包括不符合命名规范和后缀的类库,以及没有使用命名空间或者命名空间和路径不一致的类库,或者你就是想手动加载类库文件,我们都可以通过手动导入的方式加载。

我们可以使用import方法导入任何类库,用法如下:

  1. // 导入Org类库包 Library/Org/Util/Date.class.php类库
  2. import("Org.Util.Date");
  3. // 导入Home模块下面的 Application/Home/Util/UserUtil.class.php类库
  4. import("Home.Util.UserUtil");
  5. // 导入当前模块下面的类库
  6. import("@.Util.Array");
  7. // 导入Vendor类库包 Library/Vendor/Zend/Server.class.php
  8. import('Vendor.Zend.Server');

对于import方法,系统会自动识别导入类库文件的位置,ThinkPHP可以自动识别的类库包包括Think、Org、Com、Behavior和Vendor包,以及Library目录下面的子目录,如果你在Library目录下面创建了一个Test子目录,并且创建了一个UserTest.class.php类库,那么可以这样导入:

  1. import('Test.UserTest');

其他的就认为是应用类库导入。

注意,如果你的类库没有使用命名空间定义的话,实例化的时候需要加上根命名空间,例如:

  1. import('Test.UserTest');
  2. $test = new \UserTest();

按照系统的规则,import方法是无法导入具有点号的类库文件的,因为点号会直接转化成斜线,例如我们定义了一个名称为User.Info.class.php 的文件的话,采用:

  1. import("Org.User.Info");

方式加载的话就会出现错误,导致加载的文件不是Org/User.Info.class.php 文件,而是Org/User/Info.class.php 文件,这种情况下,我们可以使用:

  1. import("Org.User#Info");

来导入。

大多数情况下,import方法都能够自动识别导入类库文件的位置,如果是特殊情况的导入,需要指定import方法的第二个参数作为起始导入路径。例如,要导入当前文件所在目录下面的 RBAC/AccessDecisionManager.class.php 文件,可以使用:

  1. import("RBAC.AccessDecisionManager",dirname(__FILE__));

如果你要导入的类库文件名的后缀不是class.php而是php,那么可以使用import方法的第三个参数指定后缀:

  1. import("RBAC.AccessDecisionManager",dirname(__FILE__),".php");

注意:在Unix或者Linux主机下面是区别大小写的,所以在使用import方法的时候要注意目录名和类库名称的大小写,否则会导入失败。

如果你的第三方类库都放在Vendor目录下面,并且都以.php为类文件后缀,也没用采用命名空间的话,那么可以使用系统内置的Vendor函数简化导入。 例如,我们把 Zend 的 Filter\Dir.php 放到 Vendor 目录下面,这个时候 Dir 文件的路径就是 Vendor\Zend\Filter\Dir.php,我们使用vendor 方法导入只需要使用:

  1. Vendor('Zend.Filter.Dir');

就可以导入Dir类库了。

Vendor方法也可以支持和import方法一样的基础路径和文件名后缀参数,例如:

  1. Vendor('Zend.Filter.Dir',dirname(__FILE__),'.class.php');

0 0
原创粉丝点击