热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

php中autoload的实现例子介绍-PHP源码

autoload在php中其实是一个魔术方法了,我们可以指定类目录及规则可以自动加载类文件从而可以省去我们使用include来加载文件了,下面一直来看看关于autoload方法一些例子.
autoload在php中其实是一个魔术方法了,我们可以指定类目录及规则可以自动加载类文件从而可以省去我们使用include来加载文件了,下面一直来看看关于autoload方法一些例子.

我们在写web应用程序时通常对每个类都建立一个 PHP 源文件。为了使用这些源文件,我们就需要在每个脚本开头写大量的的包含语句(include,require)。在 PHP 5 中,不再需要这样了。我们可__autoload()函数和spl_autoload_register函数实现实现自己的加载源文件的机制,它们会在试图使用尚未被定义的类时自动调用。通过调用这些函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。本文的主要目标是讲述如何在扩展中用C语言实现自动加载源文件的机制,但是在这之前我们先熟悉一下在PHP脚本中实现自动加载的方法。

在脚本中实现自动加载

在 PHP 5 中我们可以定义一个 __autoload() 函数,它会在试图使用尚未被定义的类时自动调用,这样我们就可以定义一些自己的加载规则了。

function __autoload($class_name) {
require_once $class_name . '.php';
}

$obj = new MyClass1();
$obj2 = new MyClass2();
?>

使用spl_autoload_register我们可以一次注册多个加载函数,PHP会在试图使用尚未被定义的类时按注册顺序调用。

function autoload_services($class_name)
{
$file = 'services/' . $class_name. '.php';
if (file_exists($file))
{
require_once($file);
}
}
function autoload_vos($class_name)
{
$file = 'vos/' . $class_name. '.php';
if (file_exists($file))
{
require_once($file);
}
}
spl_autoload_register('autoload_services');
spl_autoload_register('autoload_vos');
?>

在php扩展中实现自动加载

最近在写一个php扩展,其中一个功能就是实现类的自动加载,其实也是通过在内核中调用spl_autoload_register函数来实现。使用zend API调用spl_autoload_register函数还是相对简单的,下面我们主要讲一下如何在内核中实现inclue/require/include_once/require_once等指令的功能。其实inclue/require/include_once/require_once等指令主要是读入文件编译并执行,下面的方法就是完成了这些操作,代码中有详细的注释。

/*
* loader_import首先将PHP源文件编译成op_array,然后依次执行op_array中的opcode
*/
int loader_import(char *path, int len TSRMLS_DC) {
zend_file_handle file_handle;
zend_op_array *op_array;
char realpath[MAXPATHLEN];

if (!VCWD_REALPATH(path, realpath)) {
return 0;
}

file_handle.filename = path;
file_handle.free_filename = 0;
file_handle.type = ZEND_HANDLE_FILENAME;
file_handle.opened_path = NULL;
file_handle.handle.fp = NULL;

//调用zend API编译源文件
op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC);

if (op_array && file_handle.handle.stream.handle) {
int dummy = 1;

if (!file_handle.opened_path) {
file_handle.opened_path = path;
}

//将源文件注册到执行期间的全局变量(EG)的include_files列表中,这样就标记了源文件已经包含过了
zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy,
sizeof(int), NULL);
}
zend_destroy_file_handle(&file_handle TSRMLS_CC);

//开始执行op_array
if (op_array) {
zval *result = NULL;
//保存原来的执行环境,包括active_op_array,opline_ptr等
zval ** __old_return_value_pp = EG(return_value_ptr_ptr);
zend_op ** __old_opline_ptr = EG(opline_ptr);
zend_op_array * __old_op_array = EG(active_op_array);
//保存环境完成后,初始化本次执行环境,替换op_array
EG(return_value_ptr_ptr) = &result;
EG(active_op_array) = op_array;

#if ((PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION > 2)) || (PHP_MAJOR_VERSION > 5)
if (!EG(active_symbol_table)) {
zend_rebuild_symbol_table(TSRMLS_C);
}
#endif
//调用zend API执行源文件的op_array
zend_execute(op_array TSRMLS_CC);
//op_array执行完成后销毁,要不然就要内存泄露了,哈哈
destroy_op_array(op_array TSRMLS_CC);
efree(op_array);
//通过检查执行期间的全局变量(EG)的exception是否被标记来确定是否有异常
if (!EG(exception)) {
if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) {
zval_ptr_dtor(EG(return_value_ptr_ptr));
}
}
//ok,执行到这里说明源文件的op_array已经执行完成了,我们要恢复原来的执行环境了
EG(return_value_ptr_ptr) = __old_return_value_pp;
EG(opline_ptr) = __old_opline_ptr;
EG(active_op_array) = __old_op_array;

return 1;
}
return 0;
}

推荐阅读
  • 说到C语言的语句块,真是一堆血泪史。第一大坑就是优先级。刚工作那会儿,C的书没看几本,自信满满的认为C语言都会了,拿出搞ACM培养的豪情壮志,代码倒是写得爽,却到处留 ... [详细]
  • 本文介绍了使用Python解析C语言结构体的方法,包括定义基本类型和结构体类型的字典,并提供了一个示例代码,展示了如何解析C语言结构体。 ... [详细]
  • OO第一单元自白:简单多项式导函数的设计与bug分析
    本文介绍了作者在学习OO的第一次作业中所遇到的问题及其解决方案。作者通过建立Multinomial和Monomial两个类来实现多项式和单项式,并通过append方法将单项式组合为多项式,并在此过程中合并同类项。作者还介绍了单项式和多项式的求导方法,并解释了如何利用正则表达式提取各个单项式并进行求导。同时,作者还对自己在输入合法性判断上的不足进行了bug分析,指出了自己在处理指数情况时出现的问题,并总结了被hack的原因。 ... [详细]
  • 这篇文章主要介绍了Python拼接字符串的七种方式,包括使用%、format()、join()、f-string等方法。每种方法都有其特点和限制,通过本文的介绍可以帮助读者更好地理解和运用字符串拼接的技巧。 ... [详细]
  • 本文介绍了在Windows系统上使用C语言命令行参数启动程序并传递参数的方法,包括接收参数程序的代码和bat文件的编写方法,同时给出了程序运行的结果。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • C语言判断正整数能否被整除的程序
    本文介绍了使用C语言编写的判断正整数能否被整除的程序,包括输入一个三位正整数,判断是否能被3整除且至少包含数字3的方法。同时还介绍了使用qsort函数进行快速排序的算法。 ... [详细]
  • C语言常量与变量的深入理解及其影响
    本文深入讲解了C语言中常量与变量的概念及其深入实质,强调了对常量和变量的理解对于学习指针等后续内容的重要性。详细介绍了常量的分类和特点,以及变量的定义和分类。同时指出了常量和变量在程序中的作用及其对内存空间的影响,类似于const关键字的只读属性。此外,还提及了常量和变量在实际应用中可能出现的问题,如段错误和野指针。 ... [详细]
  • 恶意软件分析的最佳编程语言及其应用
    本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • 本文介绍了200个经典c语言源代码,包括函数的使用,如sqrt函数、clanguagefunct等。这些源代码可以帮助读者更好地理解c语言的编程方法,并提供了实际应用的示例。 ... [详细]
  • 本文讲述了作者从最初对软件工程的选择迷茫到逐渐喜欢并坚持学习的经历。作者在大学期间通过学习专业课和参与项目开发,不断挑战自己并取得成就感。虽然曾考虑过转专业和复读,但最终决定坚持学习软件工程,并为自己的未来努力奋斗。作者还提到了大学生活与自己最初的预期不同,但对此并没有太多抱怨。 ... [详细]
  • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 《2017年3月全国计算机等级考试二级C语言上机题库完全版》由会员分享,可在线阅读,更多相关《2017年3月全国计算机等级考试二级C语言上机题库完全版( ... [详细]
author-avatar
静乐思
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有