PHP __autoload机制原理
时间:2012-09-25
来源:互联网
http://liexusong.sinaapp.com/?p=261
__autoload机制是PHP5引入的一种自动执行的机制,当new一个不存在的对象时,PHP便会执行__autoload函数的代码。而你可以在__autoload函数中引入需要的类文件,这样就不必每个同时引入一大堆的类库,只需要必要的时候才引入。例如:
如果PHP找不到MyObject类,便会执行__autoload函数,这样就可以自动引入这个类文件。
那么在PHP内部是怎么实现这个机制的呢?
当在PHP脚本new一个对象的时候,PHP内核会调用zend_lookup_class()函数,而这个函数的作用是从PHP的类表(存放类的HashTable)中查找要进行new操作的类。如果没有找到,便会调用用户自动的__autoload函数,zend_lookup_class()函数的代码如下:
从上面的代码可以知道,使用__autoload机制会调用从类表中查找两次要进行new操作的类,而且还调用了一次__autoload函数。所以性能肯定比不上直接手工引入类文件。不过这个机制的好处就是方便,所以如果不是很在意性能的问题的话,__autoload机制是一个不错的选择。
__autoload机制是PHP5引入的一种自动执行的机制,当new一个不存在的对象时,PHP便会执行__autoload函数的代码。而你可以在__autoload函数中引入需要的类文件,这样就不必每个同时引入一大堆的类库,只需要必要的时候才引入。例如:
<?php function __autoload($classname) { require(PATH_TO_CLASS.'/'.$classname.'.class.php'); } $obj = new MyObject(); ?>
如果PHP找不到MyObject类,便会执行__autoload函数,这样就可以自动引入这个类文件。
那么在PHP内部是怎么实现这个机制的呢?
当在PHP脚本new一个对象的时候,PHP内核会调用zend_lookup_class()函数,而这个函数的作用是从PHP的类表(存放类的HashTable)中查找要进行new操作的类。如果没有找到,便会调用用户自动的__autoload函数,zend_lookup_class()函数的代码如下:
ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) { zval **args[1]; zval autoload_function; zval class_name, *class_name_ptr = &class_name; zval *retval_ptr; int retval; char *lc_name; zval *exception; char dummy = 1; lc_name = do_alloca(name_length + 1); /* 把类名转换成小写 */ zend_str_tolower_copy(lc_name, name, name_length); /* 查找要进行new操作的类 */ if (zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce) == SUCCESS) {/* 找到的话,返回SUCCESS */ free_alloca(lc_name); return SUCCESS; } if (zend_is_compiling(TSRMLS_C)) { free_alloca(lc_name); return FAILURE; } /* 找不到要进行new操作的类 */ if (EG(in_autoload) == NULL) { ALLOC_HASHTABLE(EG(in_autoload)); zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0); } if (zend_hash_add(EG(in_autoload), lc_name, name_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { free_alloca(lc_name); return FAILURE; } /* 构建一个__autoload函数名变量 */ ZVAL_STRINGL(&autoload_function, "__autoload", sizeof("__autoload")-1, 0); /* 要进行new操作的类名 */ INIT_PZVAL(class_name_ptr); ZVAL_STRINGL(class_name_ptr, name, name_length, 0); args[0] = &class_name_ptr; exception = EG(exception); EG(exception) = NULL; /* 调用用户自定义的__autoload函数 */ retval = call_user_function_ex(EG(function_table), NULL, &autoload_function, &retval_ptr, 1, args, 0, NULL TSRMLS_CC); zend_hash_del(EG(in_autoload), lc_name, name_length+1); if (retval == FAILURE) { EG(exception) = exception; free_alloca(lc_name); return FAILURE; } if (EG(exception)) { free_alloca(lc_name); zend_error(E_ERROR, "__autoload(%s) threw an exception of type '%s'", name, Z_OBJCE_P(EG(exception))->name); return FAILURE; } EG(exception) = exception; zval_ptr_dtor(&retval_ptr); /* 再一次从类表中查找要进行new操作的类 */ retval = zend_hash_find(EG(class_table), lc_name, name_length + 1, (void **) ce); free_alloca(lc_name); return retval; }
从上面的代码可以知道,使用__autoload机制会调用从类表中查找两次要进行new操作的类,而且还调用了一次__autoload函数。所以性能肯定比不上直接手工引入类文件。不过这个机制的好处就是方便,所以如果不是很在意性能的问题的话,__autoload机制是一个不错的选择。
作者: liexusong 发布时间: 2012-09-25
学习了
作者: qianxunww 发布时间: 2012-10-25
谢谢了 好东西
作者: yangtze 发布时间: 2013-03-28
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28