Skip to content

Latest commit

 

History

History
90 lines (71 loc) · 2.76 KB

pch-007.md

File metadata and controls

90 lines (71 loc) · 2.76 KB

New Includes Function -- spl_autoload()

author: ryat#www.wolvez.org date:2009-04-13

1.描述

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

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方法

2.代码分析

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方法的使用方法的话,你可能很快就会意识到这点了:)]

3.测试代码

PoC:

// test.php
<?php

spl_autoload('info', '.txt');

// info.txt
<?php

phpinfo();