Skip to content

Commit 5b59d49

Browse files
committed
Cleanup SPL autoload implementation
Replace EG(autoload_func) with a C level zend_autoload hook. This avoids having to do one indirection through PHP function calls. The need for EG(autoload_func) was a leftover from the __autoload() implementation. Additionally, drop special-casing of spl_autoload(), and instead register it just like any other autoloading function. This fixes bug #71236 as a side-effect. Finally, change spl_autoload_functions() to always return an array. The distinction between false and an empty array no longer makes sense here. Closes GH-5696.
1 parent 68dd6cc commit 5b59d49

15 files changed

+164
-218
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ PHP NEWS
160160
- SQLite3:
161161
. Added SQLite3::setAuthorizer() and respective class constants. (bohwaz)
162162

163+
- SPL:
164+
. Fixed bug #71236 (Second call of spl_autoload_register() does nothing if it
165+
has no arguments). (Nikita)
166+
163167
- Standard:
164168
. Implemented FR #78638 (__PHP_Incomplete_Class should be final). (Laruence)
165169
. Fixed bug #77204 (getimagesize(): Read error! should mention file path).

Zend/tests/bug49908.phpt

+3-5
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ string(3) "Bar"
2929

3030
Fatal error: Uncaught Exception: Bar in %s:%d
3131
Stack trace:
32-
#0 [internal function]: {closure}('Bar')
33-
#1 %s(%d): spl_autoload_call('Bar')
34-
#2 [internal function]: {closure}('Foo')
35-
#3 %s(%d): spl_autoload_call('Foo')
36-
#4 {main}
32+
#0 %s(%d): {closure}('Bar')
33+
#1 %s(%d): {closure}('Foo')
34+
#2 {main}
3735
thrown in %s on line %d

Zend/tests/generators/bug65161.phpt

+3-4
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ foreach (testGenerator() as $i);
1919
--EXPECTF--
2020
Fatal error: Uncaught Error: Call to undefined function foo() in %s:%d
2121
Stack trace:
22-
#0 [internal function]: autoload('SyntaxError')
23-
#1 %s(%d): spl_autoload_call('SyntaxError')
24-
#2 %s(%d): testGenerator()
25-
#3 {main}
22+
#0 %s(%d): autoload('SyntaxError')
23+
#1 %s(%d): testGenerator()
24+
#2 {main}
2625
thrown in %s on line %d

Zend/tests/type_declarations/variance/loading_exception1.phpt

+2-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,5 @@ Class A does not exist
4444

4545
Fatal error: During inheritance of B with variance dependencies: Uncaught Exception: Class A does not exist in %s:%d
4646
Stack trace:
47-
#0 [internal function]: {closure}('A')
48-
#1 %s(%d): spl_autoload_call('A')
49-
#2 {main} in %s on line %d
47+
#0 %s(%d): {closure}('A')
48+
#1 {main} in %s on line %d

Zend/tests/type_declarations/variance/loading_exception2.phpt

+2-3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,5 @@ Class I does not exist
4646

4747
Fatal error: During inheritance of B with variance dependencies: Uncaught Exception: Class I does not exist in %s:%d
4848
Stack trace:
49-
#0 [internal function]: {closure}('I')
50-
#1 %s(%d): spl_autoload_call('I')
51-
#2 {main} in %s on line %d
49+
#0 %s(%d): {closure}('I')
50+
#1 {main} in %s on line %d

Zend/tests/use_unlinked_class.phpt

+2-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ class A implements I {
1515
Fatal error: Uncaught ReflectionException: Class A does not exist in %s:%d
1616
Stack trace:
1717
#0 %s(%d): ReflectionClass->__construct('A')
18-
#1 [internal function]: {closure}('I')
19-
#2 %s(%d): spl_autoload_call('I')
20-
#3 {main}
18+
#1 %s(%d): {closure}('I')
19+
#2 {main}
2120
thrown in %s on line %d

Zend/zend_execute.h

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ struct _zend_fcall_info;
3131
ZEND_API extern void (*zend_execute_ex)(zend_execute_data *execute_data);
3232
ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value);
3333

34+
/* The lc_name may be stack allocated! */
35+
ZEND_API extern zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_name);
36+
3437
void init_executor(void);
3538
void shutdown_executor(void);
3639
void shutdown_destructors(void);

Zend/zend_execute_API.c

+10-35
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444

4545
ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data);
4646
ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value);
47+
ZEND_API zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_name);
4748

4849
/* true globals */
4950
ZEND_API const zend_fcall_info empty_fcall_info = {0};
@@ -140,7 +141,6 @@ void init_executor(void) /* {{{ */
140141
EG(class_table) = CG(class_table);
141142

142143
EG(in_autoload) = NULL;
143-
EG(autoload_func) = NULL;
144144
EG(error_handling) = EH_NORMAL;
145145
EG(flags) = EG_FLAGS_INITIAL;
146146

@@ -913,11 +913,9 @@ ZEND_API void zend_call_known_instance_method_with_2_params(
913913
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, uint32_t flags) /* {{{ */
914914
{
915915
zend_class_entry *ce = NULL;
916-
zval args[1], *zv;
917-
zval local_retval;
916+
zval *zv;
918917
zend_string *lc_name;
919-
zend_fcall_info fcall_info;
920-
zend_fcall_info_cache fcall_cache;
918+
zend_string *autoload_name;
921919

922920
if (key) {
923921
lc_name = key;
@@ -952,25 +950,22 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
952950
return ce;
953951
}
954952

955-
/* The compiler is not-reentrant. Make sure we __autoload() only during run-time
956-
* (doesn't impact functionality of __autoload()
957-
*/
953+
/* The compiler is not-reentrant. Make sure we autoload only during run-time. */
958954
if ((flags & ZEND_FETCH_CLASS_NO_AUTOLOAD) || zend_is_compiling()) {
959955
if (!key) {
960956
zend_string_release_ex(lc_name, 0);
961957
}
962958
return NULL;
963959
}
964960

965-
if (!EG(autoload_func)) {
961+
if (!zend_autoload) {
966962
if (!key) {
967963
zend_string_release_ex(lc_name, 0);
968964
}
969965
return NULL;
970-
971966
}
972967

973-
/* Verify class name before passing it to __autoload() */
968+
/* Verify class name before passing it to the autoloader. */
974969
if (!key && strspn(ZSTR_VAL(name), "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\") != ZSTR_LEN(name)) {
975970
zend_string_release_ex(lc_name, 0);
976971
return NULL;
@@ -988,39 +983,19 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
988983
return NULL;
989984
}
990985

991-
ZVAL_UNDEF(&local_retval);
992-
993986
if (ZSTR_VAL(name)[0] == '\\') {
994-
ZVAL_STRINGL(&args[0], ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
987+
autoload_name = zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
995988
} else {
996-
ZVAL_STR_COPY(&args[0], name);
989+
autoload_name = zend_string_copy(name);
997990
}
998991

999-
fcall_info.size = sizeof(fcall_info);
1000-
ZVAL_STR_COPY(&fcall_info.function_name, EG(autoload_func)->common.function_name);
1001-
fcall_info.retval = &local_retval;
1002-
fcall_info.param_count = 1;
1003-
fcall_info.params = args;
1004-
fcall_info.object = NULL;
1005-
fcall_info.no_separation = 1;
1006-
1007-
fcall_cache.function_handler = EG(autoload_func);
1008-
fcall_cache.called_scope = NULL;
1009-
fcall_cache.object = NULL;
1010-
1011992
zend_exception_save();
1012-
if ((zend_call_function(&fcall_info, &fcall_cache) == SUCCESS) && !EG(exception)) {
1013-
ce = zend_hash_find_ptr(EG(class_table), lc_name);
1014-
}
993+
ce = zend_autoload(autoload_name, lc_name);
1015994
zend_exception_restore();
1016995

1017-
zval_ptr_dtor(&args[0]);
1018-
zval_ptr_dtor_str(&fcall_info.function_name);
1019-
996+
zend_string_release_ex(autoload_name, 0);
1020997
zend_hash_del(EG(in_autoload), lc_name);
1021998

1022-
zval_ptr_dtor(&local_retval);
1023-
1024999
if (!key) {
10251000
zend_string_release_ex(lc_name, 0);
10261001
}

Zend/zend_globals.h

-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ struct _zend_executor_globals {
176176
uint32_t persistent_classes_count;
177177

178178
HashTable *in_autoload;
179-
zend_function *autoload_func;
180179
zend_bool full_tables_cleanup;
181180

182181
/* for extended information support */

0 commit comments

Comments
 (0)