Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions Zend/zend_autoload.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Gina Peter Banyard <girgias@php.net> |
+----------------------------------------------------------------------+
*/

#include "zend.h"
#include "zend_API.h"
#include "zend_autoload.h"
#include "zend_hash.h"
#include "zend_types.h"
#include "zend_exceptions.h"
#include "zend_string.h"

ZEND_TLS HashTable *zend_class_autoload_functions;

static void zend_autoload_callback_zval_destroy(zval *element)
{
zend_fcall_info_cache *fcc = Z_PTR_P(element);
zend_fcc_dtor(fcc);
efree(fcc);
}

static Bucket *autoload_find_registered_function(const HashTable *autoloader_table, const zend_fcall_info_cache *function_entry)
{
zend_fcall_info_cache *current_function_entry;
ZEND_HASH_MAP_FOREACH_PTR(autoloader_table, current_function_entry) {
if (zend_fcc_equals(current_function_entry, function_entry)) {
return _p;
}
} ZEND_HASH_FOREACH_END();
return NULL;
}

ZEND_API zend_class_entry *zend_perform_class_autoload(zend_string *class_name, zend_string *lc_name)
{
if (!zend_class_autoload_functions) {
return NULL;
}

zval zname;
ZVAL_STR(&zname, class_name);

const HashTable *class_autoload_functions = zend_class_autoload_functions;

/* Cannot use ZEND_HASH_MAP_FOREACH_PTR here as autoloaders may be
* added/removed during autoloading. */
HashPosition pos;
zend_hash_internal_pointer_reset_ex(class_autoload_functions, &pos);
while (true) {
zend_fcall_info_cache *func_info = zend_hash_get_current_data_ptr_ex(class_autoload_functions, &pos);
if (!func_info) {
break;
}
zend_call_known_fcc(func_info, /* retval */ NULL, /* param_count */ 1, /* params */ &zname, /* named_params */ NULL);

if (EG(exception)) {
return NULL;
}
if (ZSTR_HAS_CE_CACHE(class_name) && ZSTR_GET_CE_CACHE(class_name)) {
return (zend_class_entry*)ZSTR_GET_CE_CACHE(class_name);
}

zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lc_name);
if (ce) {
return ce;
}

zend_hash_move_forward_ex(class_autoload_functions, &pos);
}
return NULL;
}

/* Needed for compatibility with spl_register_autoload() */
ZEND_API void zend_autoload_register_class_loader(zend_fcall_info_cache *fcc, bool prepend)
{
ZEND_ASSERT(ZEND_FCC_INITIALIZED(*fcc));

if (!zend_class_autoload_functions) {
ALLOC_HASHTABLE(zend_class_autoload_functions);
zend_hash_init(zend_class_autoload_functions, 1, NULL, zend_autoload_callback_zval_destroy, false);
/* Initialize as non-packed hash table for prepend functionality. */
zend_hash_real_init_mixed(zend_class_autoload_functions);
}

ZEND_ASSERT(
fcc->function_handler->type != ZEND_INTERNAL_FUNCTION
|| !zend_string_equals_literal(fcc->function_handler->common.function_name, "spl_autoload_call")
);

/* If function is already registered, don't do anything */
if (autoload_find_registered_function(zend_class_autoload_functions, fcc)) {
/* Release potential call trampoline */
zend_release_fcall_info_cache(fcc);
return;
}

zend_fcc_addref(fcc);
zend_hash_next_index_insert_mem(zend_class_autoload_functions, fcc, sizeof(zend_fcall_info_cache));
if (prepend && zend_hash_num_elements(zend_class_autoload_functions) > 1) {
/* Move the newly created element to the head of the hashtable */
ZEND_ASSERT(!HT_IS_PACKED(zend_class_autoload_functions));
Bucket tmp = zend_class_autoload_functions->arData[zend_class_autoload_functions->nNumUsed-1];
memmove(zend_class_autoload_functions->arData + 1, zend_class_autoload_functions->arData, sizeof(Bucket) * (zend_class_autoload_functions->nNumUsed - 1));
zend_class_autoload_functions->arData[0] = tmp;
zend_hash_rehash(zend_class_autoload_functions);
}
}

ZEND_API bool zend_autoload_unregister_class_loader(const zend_fcall_info_cache *fcc) {
if (zend_class_autoload_functions) {
Bucket *p = autoload_find_registered_function(zend_class_autoload_functions, fcc);
if (p) {
zend_hash_del_bucket(zend_class_autoload_functions, p);
return true;
}
}
return false;
}

ZEND_API zend_array* zend_autoload_fcc_map_to_callable_zval_map(void) {
if (zend_class_autoload_functions) {
zend_fcall_info_cache *fcc;

zend_array *map = zend_new_array(zend_hash_num_elements(zend_class_autoload_functions));
ZEND_HASH_MAP_FOREACH_PTR(zend_class_autoload_functions, fcc) {
zval tmp;
zend_get_callable_zval_from_fcc(fcc, &tmp);
zend_hash_next_index_insert(map, &tmp);
} ZEND_HASH_FOREACH_END();
return map;
}
return (zend_array*)&zend_empty_array;
}

/* Only for deprecated strange behaviour of spl_autoload_unregister() */
ZEND_API void zend_autoload_clean_class_loaders(void)
{
if (zend_class_autoload_functions) {
/* Don't destroy the hash table, as we might be iterating over it right now. */
zend_hash_clean(zend_class_autoload_functions);
}
}

void zend_autoload_shutdown(void)
{
if (zend_class_autoload_functions) {
zend_hash_destroy(zend_class_autoload_functions);
FREE_HASHTABLE(zend_class_autoload_functions);
zend_class_autoload_functions = NULL;
}
}
30 changes: 30 additions & 0 deletions Zend/zend_autoload.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Gina Peter Banyard <girgias@php.net> |
+----------------------------------------------------------------------+
*/

#include "zend_string.h"
#include "zend_hash.h"
#include "zend_API.h"
#include "zend.h"

ZEND_API zend_class_entry *zend_perform_class_autoload(zend_string *class_name, zend_string *lc_name);
ZEND_API void zend_autoload_register_class_loader(zend_fcall_info_cache *fcc, bool prepend);
ZEND_API bool zend_autoload_unregister_class_loader(const zend_fcall_info_cache *fcc);
ZEND_API zend_array* zend_autoload_fcc_map_to_callable_zval_map(void);
/* Only for deprecated strange behaviour of spl_autoload_unregister() */
ZEND_API void zend_autoload_clean_class_loaders(void);
void zend_autoload_shutdown(void);
2 changes: 2 additions & 0 deletions Zend/zend_builtin_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@
#include "zend_extensions.h"
#include "zend_closures.h"
#include "zend_generators.h"
#include "zend_autoload.h"
#include "zend_builtin_functions_arginfo.h"
#include "zend_smart_str.h"

/* }}} */

ZEND_MINIT_FUNCTION(core) { /* {{{ */
zend_autoload = zend_perform_class_autoload;
zend_register_default_classes();

zend_standard_class_def = register_class_stdClass();
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1738,6 +1738,7 @@ PHP_ADD_SOURCES([Zend], m4_normalize([
zend_ast.c
zend_atomic.c
zend_attributes.c
zend_autoload.c
zend_builtin_functions.c
zend_call_stack.c
zend_closures.c
Expand Down
Loading
Loading