New Includes Function — spl_autoload()

author: ryat#www.wolvez.org
team:http://www.80vul.com
date:2009-04-13

一、描述

看看手册对这个函数的描述:

spl_autoload
(PHP 5 >= 5.1.2)

spl_autoload — Default implementation for __autoload()

void spl_autoload ( string $class_name [, string $file_extensions= spl_autoload_extensions() ] )

This function is intended to be used as a default implementation for __autoload(). If nothing else is specified and autoload_register() is called without any parameters then this functions will be used for any later call to __autoload().

从描述中可以知道这个函数用来替代类中__autoload方法

二、代码分析

spl_autoload()的php源码:

// php_spl.c
PHP_FUNCTION(spl_autoload)
{

char *class_name, *lc_name, *file_exts = SPL_G(autoload_extensions);
int class_name_len, file_exts_len = SPL_G(autoload_extensions_len), found = 0;
char *copy, *pos1, *pos2;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “s|s”, &class_name, &class_name_len, &file_exts, &file_exts_len) == FAILURE) {
RETURN_FALSE;
}

if (file_exts == NULL) { /* autoload_extensions is not intialzed, set to defaults */
copy = pos1 = estrndup(SPL_DEFAULT_FILE_EXTENSIONS, sizeof(SPL_DEFAULT_FILE_EXTENSIONS)-1);
// 如果没有指定file_extensions参数,设定file_extensions为.inc或.php
} else {
copy = pos1 = estrndup(file_exts, file_exts_len);
}
lc_name = zend_str_tolower_dup(class_name, class_name_len);
while(pos1 && *pos1 && !EG(exception)) {

if (spl_autoload(class_name, lc_name, class_name_len, pos1 TSRMLS_CC)) {

static int spl_autoload(const char *class_name, const char * lc_name, int class_name_len, const char * file_extension TSRMLS_DC) /* {{{ */
{

class_file_len = spprintf(&class_file, 0, “%s%s”, lc_name, file_extension);
// 合并 class_name和file_extensions

ret = php_stream_open_for_zend_ex(class_file, &file_handle, ENFORCE_SAFE_MODE|USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
// 打开指定文件

if (ret == SUCCESS) {
if (!file_handle.opened_path) {
file_handle.opened_path = estrndup(class_file, class_file_len);
}
if (zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) {
new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
// 将文件编译成opcode

} else {
new_op_array = NULL;

}
if (new_op_array) {

zend_execute(new_op_array TSRMLS_CC);
// 执行opcode 🙂

可以看到,这个函数完全可以替代include/require函数的作用[当然如果你熟悉__autoload方法的使用方法的话,你可能很快就会意识到这点了:)]

三、测试代码

PoC:

// test.php

留下评论