自动加载(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 = new Demo();
事实上,我们可以看到__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 />';
}
function classLoader($className) {
echo 'SPL load class:', $className, '<br />';
}
spl_autoload_register('classLoader');
new Test();//结果: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 = new Some();
- 最快的自动方法
- 不利于维护
具体实现:
- 判断是否有类被注册。
- 判断需要加载的类是否被注册,如果已注册则加载其对应路径文件。
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 = new Example\Adapter\Some();
使用命名空间或外部库组织代码时,你可以利用注册命名空间的方式来自动加载其包含的库。
对于命名空间对应的路径,要其末尾加一个斜杠。
具体实现:
- 判断是否有命名空间被注册。
判断需要加载的类是否已以注册的命名开始。
例如注册的命名空间为
"Example\Base" => "vendor/example/base/"
"Example\Base" => "vendor/example/base/"
$test1 = new Example\Base\Test();// vendor/example/base/Test.php
$test2 = new Example\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 = new Example_Adapter_Some();
类似于命名空间,从2.1.0开始phalcon将不再支持前缀。
具体实现:
- 判断是否有前缀被注册。
判断需要加载的类是否已以前缀开始命名。
例如注册的前缀为
"Example_Base" => "vendor/example/base/"
"Example_Base" => "vendor/example/base/"
$test1 = new Example_Base_Test();// vendor/example/base/Test.php
$test2 = new Example_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 = new Some();
可以自动加载注册目录下的类文件。但是该方法在性能方面并不被推荐,因为Phalcon将在个文件夹下大量查找与类名相同的文件。在使用注册目录自动加载时,要注意注册目录的相关性,即将重要的目录放在前面。
具体实现:
- 将类名中的前缀分隔符
_
或是命名空间分隔符\
替换成文件夹分割符/
- 判断是否有文件夹被注册。
依据文件后缀构建可能的文件路径
例如注册的前缀为
"vendor/example/base/"
$test = new Test();// 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 autoloader
spl_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-loader
if (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)
- 自动加载区分大小写。
- 命名空间或前缀的方式要比文件夹的方式要快得多。
Phalcon自动加载(PHP自动加载)的更多相关文章
-
[Eclipse] - 集成JBoss7热加载和自动发布
使用Eclipse + JBoss开发时,总是要重启项目或JBoss,烦人.下面方法可以很简单的实现Eclipse + JBoss热加载和自动发布. 我的环境是JBoss 7.1.1 Final 1) ...
-
Pace.js – 超赞的页面加载进度自动指示和 Ajax 导航效果
在页面中引入 Pace.js 和您所选择主题的 CSS 文件,就可以让你的页面拥有漂亮的加载进度和 Ajax 导航效果.不需要挂接到任何代码,自动检测进展.您可以选择颜色和多种效果,有简约,闪光灯, ...
-
Java的静态代码块是否会在类被加载时自动执行?
JAVA静态代码块会在类被加载时自动执行? 一.先看Java静态方法,静态变量 http://www.cnblogs.com/winterfells/p/7906078.html 静态代码块 在类中, ...
-
jquery--blur()事件,在页面加载时自动获取焦点
jquery--blur()事件会在页面加载时自动获取焦点,应将onblur写到html标签中 <div class="inputbox"> <input typ ...
-
jquery-事件之页面框架加载后自动执行
jQuery事件之页面框架加载后自动执行 1)概述 HTML执行是按自上而下编译,而<script>一般写在body结束之前.如果在HTML加载的过程中卡住, 比如加载图片等,没有显示出来 ...
-
selenium网页没加载完成就停止加载并自动刷新
判断一个网页10秒没加载完成就停止加载并自动刷新 driver=webdriver.Chome() driver.set_page_load_timeout(10) while True: try: ...
-
[WPF自定义控件库] 让Form在加载后自动获得焦点
原文:[WPF自定义控件库] 让Form在加载后自动获得焦点 1. 需求 加载后让第一个输入框或者焦点是个很基本的功能,典型的如"登录"对话框.一般来说"登录" ...
-
动态加载(异步加载)jquery/MUI类库 页面加载完成后加载js类库
动态加载Mui类库: // ==UserScript== // @name // @version 1.4.0 // @author zzdhidden@gmail.com // @namespace ...
-
第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性)
一. 简介 上一个章节中,也介绍了立即加载和延迟加载,但上一个章节是针对单表而言的,不含外键,立即也好,延迟也好,都是指单表中的数据.但本章节重点介绍的三种加载方式均是针对含(导航属性.外键)的情况下 ...
-
Unity5 AssetBundle打包加载及服务器加载
Assetbundle为资源包不是资源 打包1:通过脚本指定打包 AssetBundleBuild ab = new AssetBundleBuild ...
随机推荐
-
java -cp
java -cp /home/hdp/log4jTest/log4j-1.2.17.jar:/home/hdp/log4jTest/testLog.jar:/home/hdp/log4jTest/co ...
-
rabbitmq批量删除队列
有些时候,我们需要批量的删除rabbitmq中的队列,尤其是对于那些客户端配置了队列不存在时自动创建,但断开时不自动删除的应用来说. rabbitmqctl并没有包含直接管理队列的功能,其提供的vho ...
-
SQLServer如何用T—SQL命令查询一个数据库中有哪些表
1.查询SQL中的所有表: Select TABLE_NAME FROM 数据库名称.INFORMATION_SCHEMA.TABLES Where TABLE_TYPE='BASE TABLE' 执 ...
-
【Java框架型项目从入门到装逼】第六节 - 用ajax请求后台数据
这一节我们来说一下如何用ajax提交请求? 我们先不讲ajax的原理,还是先以实战为主,看一下这个东西到底怎么用的? form表单: <!-- 采用post表单提交 --> <for ...
-
qt5程序打包含qml
Qt 官方开发环境使用的动态链接库方式,在发布生成的exe程序时,需要复制一大堆 dll,如果自己去复制dll,很可能丢三落四,导致exe在别的电脑里无法正常运行. 因此 Qt 官方开发环境里自带了一 ...
-
Canvas入门到高级详解(中)
三. canvas 进阶 3.1 Canvas 颜色样式和阴影 3.1.1 设置填充和描边的颜色(掌握) fillStyle : 设置或返回用于填充绘画的颜色 strokeStyle: 设置或返回用于 ...
-
nginx转发
1.下载nginx:官网(http://nginx.org)右侧下载,进入下载页,选在需要下载的版本 2.将压缩包解压到指定的目录下 (D:\Environments\nginx-1.8.0) 3.启 ...
-
Java 浅拷贝 深拷贝
两者区别主要在于引用数据类型的属性,对于基本数据类型采用的是值传递,所以两者一样: 对于浅拷贝,引用数据类型只会进行引用传递,即复制一份引用值(内存地址)给新对象,一个对象的变化会影响到另一个的引用属 ...
-
0073 javacTask: 源发行版 1.8 需要目标发行版 1.8
今天在编译执行下面这段代码的时候,编译报错:javacTask: 源发行版 1.8 需要目标发行版 1.8 public class Test { public static void main(St ...
-
ZKEACMS 自定义表单的使用
ZKEACMS Core 2.2 已经发布了,其中主要添加了自定义表单的功能.使用自定义表单的功能,您可以在几分钟内就创建一个表单,并用它来收集一些信息.导出收集的信息,就可以做一些统计分析. 创建表 ...