自动加载(phalcon\Loader)

王朝学院·作者佚名  2016-08-28
窄屏简体版  字體: 小  |  中  |  大  |  超大  

自动加载(phalcon\Loader)转载请注明来源一、php文件引入通过 include() 或 require() 函数,可以在PHP程序执行之前在该文件中插入一个文件的内容。

区别:处理错误的方式不同。include() 函数会生成一个警告(但是脚本会继续执行),而require()函数会生成一个致命错误(fatal error)(在错误发生后脚本会停止执行)

* 正因为在文件不存在或被重命名后脚本不会继续执行,因此我们推荐使用 require() 而不是 include()。

二、php类自动加载参考文章:php手册 和 PHP的类自动加载机制

在php5之前,各php框架实现类的加载,一般要按照某种约定实现一个遍历目录,自动加载符合约定条件的文件类或函数。因此在php5之前类的使用并没有现在频繁。

在php5之后,当加载php类的时候,如果类所在文件夹并没有被包含进来或是类名出错时,Zend引擎会自动调用__autoload函数。__autoload函数需要用户自己实现。

在php5.1.2版本之后,可以使用spl_autoload_register函数自定义加载处理函数。当没有调用此函数,默认情况下会使用spl自定义的spl_autoload函数。

1. php自动加载之__autoload

function__autoload($className) {$file=$className. '.php';if(is_file($file)) {require($file);

}else{echo'no this ' .$className. ' class file';

}

}$demo=newDemo();

事实上,我们可以看到__autoload至少需要做三件事(“三步走”),它们分别是:

根据类名确定类的文件名。确定类文件所在路径,上例用的是中用的是相对定位,我们的测试文件其实在同一目录下。将指定类所在文件加载到程序中。在第一步和第二步中,我们必须约定类名与文件的映射方法,只有这样我们才能够依据类名找到其所对应的文件,实现加载。

因此__autoload自动加载中,最重要的就是指定类名与其所在文件的对应关系。当有大量的类需要包含进来的时候,我们只需要确立相应的规则,然后将类名与其对应的文件进行映射,就能够实现惰性加载(lazy loading)了。

Tip:spl_autoload_register() 提供了一种更加灵活的方式来实现类的自动加载。因此,不再建议使用 __autoload() 函数,在以后的版本中它可能被弃用。

2. php自动加载之spl_autoload_register引言:如果在一个php系统实现中,使用了很多的其他类库,这些类库可能是由不同的工程师进行开发的,因此类名与其所在文件的映射规则不尽相同。这时候如果要实现类库的自动加载,就必须在__autoload函数中将所有的映射规则全部实现。这就会导致__autoload会非常复杂,甚至无法实现。同时还会使得__autoload函数十分臃肿。为将来系统的维护和性能带来很大的负面影响。(__autoload的弊端)

spl_autoload_register:注册给定的函数作为__autoload的实现。简单来说就是将函数注册之SPL的__autoload函数栈中,并移除系统默认的__autload()函数。

function__autoload($className) {echo'autload class:',$className, '<br />';

}functionclassLoader($className) {echo'SPL load class:',$className, '<br />';

}

spl_autoload_register('classLoader');newTest();//结果:SPL load class:Test

Tip:

如果在你的程序中已经实现了__autoload()函数,它必须显式注册到__autoload()队列中。因为 spl_autoload_register()函数会将Zend Engine中的__autoload()函数取代为spl_autoload()或spl_autoload_call()。相比于__autoload只能够定义一次。spl_autoload_register()函数可以定义多个autoload函数。因为spl_autoload_register创建了autoload函数队列,该队列按照定义的先后顺序逐个执行。

function __autoload($className) {

echo 'autload class:' . $className . '<br />';

}

function classLoader($className) {

echo 'SPL load class:' . $className . '<br />';

}

spl_autoload_register('classLoader');

$demo = new Demo();//结果:SPL load class:Demo

函数说明bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $PRepend = false ]]] )

autoload_function【可选】添加到自动加载栈的函数。默认为spl_autoload()。还可以调用spl_autoload_register()函数以注册一个回调函数,而不是为函数提供一个字符串名称。如提供一个如array('class','method')这样的数组,使得可以使用某个对象的方法。throw【可选】无法成功注册时,是否抛出异常prepend【可选】是否将将该函数添加到队列之首,而不是队列的尾部。备注:SPL自动加载功能是由spl_autoload() ,spl_autoload_register(), spl_autoload_functions() ,spl_autoload_extensions()和spl_autoload_call()函数提供的。

三、Phalcon的类自动加载Phalcon\Loader 通用类加载器(Universal Class Loader),意在根据协议帮助项目自动加载项目中的类(This component helps to load your project classes automatically based on some conventions)。Phalcon支持四种类加载方式,先后顺序分别是注册类名、注册命名空间、注册前缀和注册文件夹的方式。

Phalcon的默认文件后缀为php,当然你自己也可以配置(setExtensions())。

1 . 注册类名<?php$loader=new\Phalcon\Loader();$loader->registerClasses(array("Some" => "library/OtherComponent/Other/Some.php",

"Example\Base" => "vendor/example/adapters/Example/BaseClass.php",)

);$loader->register();//i.e. library/OtherComponent/Other/Some.php$some=newSome();

最快的自动方法不利于维护具体实现:

判断是否有类被注册。判断需要加载的类是否被注册,如果已注册则加载其对应路径文件。2. 注册命名空间<?php$loader=new\Phalcon\Loader();$loader->registerNamespaces(array("Example\Base" => "vendor/example/base/",

"Example\Adapter" => "vendor/example/adapter/",

"Example" => "vendor/example/",)

);$loader->register();//vendor/example/adapter/Some.php$some=newExample\Adapter\Some();

使用命名空间或外部库组织代码时,你可以利用注册命名空间的方式来自动加载其包含的库。

对于命名空间对应的路径,要其末尾加一个斜杠。

具体实现:

判断是否有命名空间被注册。判断需要加载的类是否已以注册的命名开始。

例如注册的命名空间为"Example\Base" => "vendor/example/base/"

"Example\Base" => "vendor/example/base/"$test1=newExample\Base\Test();//vendor/example/base/Test.php$test2=newExample\Test();//错误,无法加载。

名称处理:1、去掉命名指定空间前缀。2、将命名空间分隔符\转换成文件分隔符/

依据文件拓展名构建完整的文件路径,并判断该文件是否存在,如该文件存在加载。3. 注册前缀<?php$loader=new\Phalcon\Loader();$loader->registerPrefixes(array("Example_Base" => "vendor/example/base/",

"Example_Adapter" => "vendor/example/adapter/",

"Example_" => "vendor/example/",)

);$loader->register();//vendor/example/adapter/Some.php$some=newExample_Adapter_Some();

类似于命名空间,从2.1.0开始phalcon将不再支持前缀。

具体实现:

判断是否有前缀被注册。判断需要加载的类是否已以前缀开始命名。

例如注册的前缀为"Example_Base" => "vendor/example/base/"

"Example_Base" => "vendor/example/base/"$test1=newExample_Base_Test();//vendor/example/base/Test.php$test2=newExample_Test();//错误,无法加载。

名称处理:1、去掉类的前缀。2、将前缀分隔符_转换成文件分隔符/

依据文件拓展名构建完整的文件路径,并判断该文件是否存在,如该文件存在加载。4. 注册文件夹<?php$loader=new\Phalcon\Loader();$loader->registerDirs(array("library/MyComponent/",

"library/OtherComponent/Other/",

"vendor/example/adapters/",

"vendor/example/")

);$loader->register();//i.e. library/OtherComponent/Other/Some.php$some=newSome();

可以自动加载注册目录下的类文件。但是该方法在性能方面并不被推荐,因为Phalcon将在个文件夹下大量查找与类名相同的文件。在使用注册目录自动加载时,要注意注册目录的相关性,即将重要的目录放在前面。

具体实现:

将类名中的前缀分隔符_或是命名空间分隔符\替换成文件夹分割符/判断是否有文件夹被注册。依据文件后缀构建可能的文件路径

例如注册的前缀为"vendor/example/base/"

$test=newTest();//vendor/example/base/Test.php

5. 修改当前策略(Modifying current strategies)即为当前自动加载数据添加额外的值。

<?php//Adding more directories$loader->registerDirs(array("../app/library/",

"../app/plugins/"),true);

注册时添加第二个参数值true,使其与原数组合并。

6. 安全层(Security Layer)没有进行任何安全检查的自动加载器,如下:

<?php//Basic autoloaderspl_autoload_register(function($className) {if(file_exists($className. '.php')) {require$className. '.php';

}

});

假如我们没有进行任何安全检查时,如果误启了自动加载器,那么恶意准备的字符串就回作为参数访问程序中的重要文件。

<?php//This variable is not filtered and comes from an insecure source$className= '../processes/important-process';//Check if the class exists triggering the auto-loaderif(class_exists($className)) {//...}

Phalcon的做法是删除任何无用的字符串,减少被攻击的可能性。

7. 自动加载事件在下面的例子中,而不必使用类加载器,使我们获得调试信息的流程操作:

<?php$eventsManager=new\Phalcon\Events\Manager();$loader=new\Phalcon\Loader();$loader->registerNamespaces(array('Example\\Base' => 'vendor/example/base/',

'Example\\Adapter' => 'vendor/example/adapter/',

'Example' => 'vendor/example/'));//Listen all the loader events$eventsManager->attach('loader',function($event,$loader) {if($event->getType() == 'beforeCheckPath') {echo$loader->getCheckedPath();

}

});$loader->setEventsManager($eventsManager);$loader->register();

Phalcon自动加载支持以下事件:

beforeCheckClass,自动加载的过程开始前触发,当返回布尔假可以停止活动操作。pathFound,当一个类装入器定位触发afterCheckClass,自动加载的过程完成后触发。8. 注意事项(Troubleshooting)自动加载区分大小写。命名空间或前缀的方式要比文件夹的方式要快得多。

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航