/src/php-src/Zend/zend_autoload.c
Line | Count | Source |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Zend Engine | |
4 | | +----------------------------------------------------------------------+ |
5 | | | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | |
6 | | +----------------------------------------------------------------------+ |
7 | | | This source file is subject to version 2.00 of the Zend license, | |
8 | | | that is bundled with this package in the file LICENSE, and is | |
9 | | | available through the world-wide-web at the following url: | |
10 | | | http://www.zend.com/license/2_00.txt. | |
11 | | | If you did not receive a copy of the Zend license and are unable to | |
12 | | | obtain it through the world-wide-web, please send a note to | |
13 | | | license@zend.com so we can mail you a copy immediately. | |
14 | | +----------------------------------------------------------------------+ |
15 | | | Authors: Gina Peter Banyard <girgias@php.net> | |
16 | | +----------------------------------------------------------------------+ |
17 | | */ |
18 | | |
19 | | #include "zend.h" |
20 | | #include "zend_API.h" |
21 | | #include "zend_autoload.h" |
22 | | #include "zend_hash.h" |
23 | | #include "zend_types.h" |
24 | | #include "zend_exceptions.h" |
25 | | #include "zend_string.h" |
26 | | |
27 | | ZEND_TLS HashTable *zend_class_autoload_functions; |
28 | | |
29 | | static void zend_autoload_callback_zval_destroy(zval *element) |
30 | 462 | { |
31 | 462 | zend_fcall_info_cache *fcc = Z_PTR_P(element); |
32 | 462 | zend_fcc_dtor(fcc); |
33 | 462 | efree(fcc); |
34 | 462 | } |
35 | | |
36 | | static Bucket *autoload_find_registered_function(const HashTable *autoloader_table, const zend_fcall_info_cache *function_entry) |
37 | 472 | { |
38 | 472 | zend_fcall_info_cache *current_function_entry; |
39 | 996 | ZEND_HASH_MAP_FOREACH_PTR(autoloader_table, current_function_entry) { |
40 | 996 | if (zend_fcc_equals(current_function_entry, function_entry)) { |
41 | 10 | return _p; |
42 | 10 | } |
43 | 996 | } ZEND_HASH_FOREACH_END(); |
44 | 462 | return NULL; |
45 | 472 | } |
46 | | |
47 | | ZEND_API zend_class_entry *zend_perform_class_autoload(zend_string *class_name, zend_string *lc_name) |
48 | 117k | { |
49 | 117k | if (!zend_class_autoload_functions) { |
50 | 116k | return NULL; |
51 | 116k | } |
52 | | |
53 | 994 | zval zname; |
54 | 994 | ZVAL_STR(&zname, class_name); |
55 | | |
56 | 994 | const HashTable *class_autoload_functions = zend_class_autoload_functions; |
57 | | |
58 | | /* Cannot use ZEND_HASH_MAP_FOREACH_PTR here as autoloaders may be |
59 | | * added/removed during autoloading. */ |
60 | 994 | HashPosition pos; |
61 | 994 | zend_hash_internal_pointer_reset_ex(class_autoload_functions, &pos); |
62 | 1.09k | while (true) { |
63 | 1.09k | zend_fcall_info_cache *func_info = zend_hash_get_current_data_ptr_ex(class_autoload_functions, &pos); |
64 | 1.09k | if (!func_info) { |
65 | 84 | break; |
66 | 84 | } |
67 | 1.00k | zend_call_known_fcc(func_info, /* retval */ NULL, /* param_count */ 1, /* params */ &zname, /* named_params */ NULL); |
68 | | |
69 | 1.00k | if (EG(exception)) { |
70 | 273 | return NULL; |
71 | 273 | } |
72 | 734 | if (ZSTR_HAS_CE_CACHE(class_name) && ZSTR_GET_CE_CACHE(class_name)) { |
73 | 255 | return (zend_class_entry*)ZSTR_GET_CE_CACHE(class_name); |
74 | 255 | } |
75 | | |
76 | 479 | zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lc_name); |
77 | 479 | if (ce) { |
78 | 241 | return ce; |
79 | 241 | } |
80 | | |
81 | 238 | zend_hash_move_forward_ex(class_autoload_functions, &pos); |
82 | 238 | } |
83 | 225 | return NULL; |
84 | 994 | } |
85 | | |
86 | | /* Needed for compatibility with spl_register_autoload() */ |
87 | | ZEND_API void zend_autoload_register_class_loader(zend_fcall_info_cache *fcc, bool prepend) |
88 | 472 | { |
89 | 472 | ZEND_ASSERT(ZEND_FCC_INITIALIZED(*fcc)); |
90 | | |
91 | 472 | if (!zend_class_autoload_functions) { |
92 | 446 | ALLOC_HASHTABLE(zend_class_autoload_functions); |
93 | 446 | zend_hash_init(zend_class_autoload_functions, 1, NULL, zend_autoload_callback_zval_destroy, false); |
94 | | /* Initialize as non-packed hash table for prepend functionality. */ |
95 | 446 | zend_hash_real_init_mixed(zend_class_autoload_functions); |
96 | 446 | } |
97 | | |
98 | 472 | ZEND_ASSERT( |
99 | 472 | fcc->function_handler->type != ZEND_INTERNAL_FUNCTION |
100 | 472 | || !zend_string_equals_literal(fcc->function_handler->common.function_name, "spl_autoload_call") |
101 | 472 | ); |
102 | | |
103 | | /* If function is already registered, don't do anything */ |
104 | 472 | if (autoload_find_registered_function(zend_class_autoload_functions, fcc)) { |
105 | | /* Release potential call trampoline */ |
106 | 10 | zend_release_fcall_info_cache(fcc); |
107 | 10 | return; |
108 | 10 | } |
109 | | |
110 | 462 | zend_fcc_addref(fcc); |
111 | 462 | zend_hash_next_index_insert_mem(zend_class_autoload_functions, fcc, sizeof(zend_fcall_info_cache)); |
112 | 462 | if (prepend && zend_hash_num_elements(zend_class_autoload_functions) > 1) { |
113 | | /* Move the newly created element to the head of the hashtable */ |
114 | 16 | ZEND_ASSERT(!HT_IS_PACKED(zend_class_autoload_functions)); |
115 | 16 | Bucket tmp = zend_class_autoload_functions->arData[zend_class_autoload_functions->nNumUsed-1]; |
116 | 16 | memmove(zend_class_autoload_functions->arData + 1, zend_class_autoload_functions->arData, sizeof(Bucket) * (zend_class_autoload_functions->nNumUsed - 1)); |
117 | 16 | zend_class_autoload_functions->arData[0] = tmp; |
118 | 16 | zend_hash_rehash(zend_class_autoload_functions); |
119 | 16 | } |
120 | 462 | } |
121 | | |
122 | 0 | ZEND_API bool zend_autoload_unregister_class_loader(const zend_fcall_info_cache *fcc) { |
123 | 0 | if (zend_class_autoload_functions) { |
124 | 0 | Bucket *p = autoload_find_registered_function(zend_class_autoload_functions, fcc); |
125 | 0 | if (p) { |
126 | 0 | zend_hash_del_bucket(zend_class_autoload_functions, p); |
127 | 0 | return true; |
128 | 0 | } |
129 | 0 | } |
130 | 0 | return false; |
131 | 0 | } |
132 | | |
133 | | /* We do not return a HashTable* because zend_empty_array is not collectable, |
134 | | * therefore the zval holding this value must do so. Something that ZVAL_EMPTY_ARRAY(); does. */ |
135 | 0 | ZEND_API void zend_autoload_fcc_map_to_callable_zval_map(zval *return_value) { |
136 | 0 | if (zend_class_autoload_functions) { |
137 | 0 | zend_fcall_info_cache *fcc; |
138 | |
|
139 | 0 | zend_array *map = zend_new_array(zend_hash_num_elements(zend_class_autoload_functions)); |
140 | 0 | ZEND_HASH_MAP_FOREACH_PTR(zend_class_autoload_functions, fcc) { |
141 | 0 | zval tmp; |
142 | 0 | zend_get_callable_zval_from_fcc(fcc, &tmp); |
143 | 0 | zend_hash_next_index_insert(map, &tmp); |
144 | 0 | } ZEND_HASH_FOREACH_END(); |
145 | 0 | RETURN_ARR(map); |
146 | 0 | } |
147 | 0 | RETURN_EMPTY_ARRAY(); |
148 | 0 | } |
149 | | |
150 | | /* Only for deprecated strange behaviour of spl_autoload_unregister() */ |
151 | | ZEND_API void zend_autoload_clean_class_loaders(void) |
152 | 0 | { |
153 | 0 | if (zend_class_autoload_functions) { |
154 | | /* Don't destroy the hash table, as we might be iterating over it right now. */ |
155 | 0 | zend_hash_clean(zend_class_autoload_functions); |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | void zend_autoload_shutdown(void) |
160 | 191k | { |
161 | 191k | if (zend_class_autoload_functions) { |
162 | 446 | zend_hash_destroy(zend_class_autoload_functions); |
163 | 446 | FREE_HASHTABLE(zend_class_autoload_functions); |
164 | | zend_class_autoload_functions = NULL; |
165 | 446 | } |
166 | 191k | } |