__autoload 内部实现原理

__autoload  

官方:尝试加载未定义的类。我的理解是在New 对象的时候,会将对象名传递。

<?php
function __autoload($class_name) { 
    echo '加载的类名:'.$class_name;
} 

@$a = new iwonmo(); 
@$a = new iwonmo1();

运行结果输出:加载的类名:iwonmo

当New的类不存在时,可以通过这个函数进行include/require。

不过注意官方的警告:This feature has been DEPRECATED as of PHP 7.2.0. Relying on this feature is highly discouraged. 在7.2.0以后的版本被弃用

SPL

SPL的全称是:Standard PHP Library (PHP标准库),版本:PHP 5 >= 5.1.0, PHP 7,这个库是做什么用的,在官网也有解释,只不过需要看英文版,因为中文版的介绍实际是不全的,不单单是这个解释。所以看PHP的文档尽量看英文版的。

The Standard PHP Library (SPL) is a collection of interfaces and classes that are meant to solve common problems.

No external libraries are needed to build this extension and it is available and compiled by default in PHP 5.0.0.

SPL provides a set of standard datastructure, a set of iterators to traverse over objects, a set of interfaces, a set of standard Exceptions, a number of classes to work with files and it provides a set of functions like spl_autoload_register()


大致的意思是SPL是一个解决常见问题接口或者的集合。然后里面提供了一组叫做SPL的函数。另外(英文里不包含):SPL函数也取代了__autoload。

spl_autoload_register的官方解释里有这么一句话:如果在你的程序中已经实现了__autoload()函数,它必须显式注册(explicitly registered )到__autoload()队列中。因为 spl_autoload_register()函数会将Zend Engine中的__autoload()函数取代为spl_autoload()或spl_autoload_call()。

对于这组函数可以翻阅PHP的源代码(php_spl.c):

int spl_autoload(const char *class_name, const char * lc_name, int class_name_len, const char * file_extension TSRMLS_DC) /* {{{ */
{
    char *class_file;
    int class_file_len;
    int dummy = 1;
    zend_file_handle file_handle;
    zend_op_array *new_op_array;
    zval *result = NULL;

    class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension);

    if (zend_stream_open(class_file, &file_handle TSRMLS_CC) == 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);
            zend_destroy_file_handle(&file_handle TSRMLS_CC);
        } else {
            new_op_array = NULL;
            zend_file_handle_dtor(&file_handle);
        }
        if (new_op_array) {
            EG(return_value_ptr_ptr) = &result;
            EG(active_op_array) = new_op_array;
    
            zend_execute(new_op_array TSRMLS_CC);
    
            destroy_op_array(new_op_array TSRMLS_CC);
            efree(new_op_array);
            if (!EG(exception)) {
                if (EG(return_value_ptr_ptr)) {
                    zval_ptr_dtor(EG(return_value_ptr_ptr));
                }
            }

            efree(class_file);
            return zend_hash_exists(EG(class_table), (char*)lc_name, class_name_len+1);
        }
    }
    efree(class_file);
    return 0;
} /* }}} */

大致就是找到这个文件,然后编译成OP代码,然后执行,释放。实际这个过程也是__autoload的过程。这里有一个地方是会将对象名转换为小写,不知道这段代码的意义。不过明白大致意思就可以。file_extension由于被宏定义,所以这里它是一个上下文。


个人理解,如有错误还望指出。


__autoload 内部实现原理


本站如无特别说明即为原创,转而告知:(http://iwonmo.com/archives/1551.html)

标签: spl_autoload_register, 自动加载

添加新评论