Skip to content

Commit f13b4ff

Browse files
committed
Initial implementation, class autoloading works
1 parent fd4844e commit f13b4ff

File tree

8 files changed

+274
-74
lines changed

8 files changed

+274
-74
lines changed

Zend/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ libZend_la_SOURCES=\
1515
zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \
1616
zend_ini.c zend_qsort.c zend_objects.c zend_object_handlers.c \
1717
zend_objects_API.c zend_ts_hash.c zend_stream.c \
18-
zend_default_classes.c \
18+
zend_default_classes.c zend_autoload.c \
1919
zend_iterators.c zend_interfaces.c zend_exceptions.c \
2020
zend_strtod.c zend_closures.c zend_float.c zend_string.c zend_signal.c \
2121
zend_generators.c zend_virtual_cwd.c zend_ast.c

Zend/zend_autoload.c

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Zend Engine |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 1998-2014 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+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Anthony Ferrara <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
/* $Id$ */
20+
21+
#include "zend.h"
22+
#include "zend_API.h"
23+
#include "zend_autoload.h"
24+
#include "zend_hash.h"
25+
#include "zend_types.h"
26+
#include "zend_exceptions.h"
27+
#include "zend_interfaces.h"
28+
29+
#define HT_MOVE_TAIL_TO_HEAD(ht) \
30+
do { \
31+
Bucket tmp = (ht)->arData[(ht)->nNumUsed-1]; \
32+
memmove((ht)->arData + 1, (ht)->arData, \
33+
sizeof(Bucket) * ((ht)->nNumUsed - 1)); \
34+
(ht)->arData[0] = tmp; \
35+
zend_hash_rehash(ht); \
36+
} while (0)
37+
38+
39+
void* zend_autoload_call(zend_string *name, zend_string *lname, long type)
40+
{
41+
HashTable *symbol_table, *stack;
42+
zval dummy, ztype, zname, retval;
43+
zend_autoload_func *func_info;
44+
45+
ZVAL_UNDEF(&dummy);
46+
ZVAL_LONG(&ztype, type);
47+
ZVAL_STR(&zname, name);
48+
49+
switch (type) {
50+
case ZEND_AUTOLOAD_CLASS:
51+
symbol_table = EG(class_table);
52+
stack = &EG(autoload.stack.class);
53+
break;
54+
case ZEND_AUTOLOAD_FUNCTION:
55+
symbol_table = EG(function_table);
56+
stack = &EG(autoload.stack.function);
57+
break;
58+
case ZEND_AUTOLOAD_CONSTANT:
59+
symbol_table = EG(zend_constants);
60+
stack = &EG(autoload.stack.constant);
61+
break;
62+
default:
63+
return NULL;
64+
}
65+
66+
if (zend_hash_num_elements(&EG(autoload.functions)) == 0) {
67+
if (type == ZEND_AUTOLOAD_CLASS) {
68+
zend_function *call = EG(autoload.legacy);
69+
if (!call) {
70+
call = (zend_function*) zend_hash_str_find_ptr(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME));
71+
EG(autoload.legacy) = call;
72+
}
73+
if (call) {
74+
zend_call_method_with_1_params(NULL, NULL, &call, ZEND_AUTOLOAD_FUNC_NAME, &retval, &zname);
75+
return zend_hash_find_ptr(symbol_table, lname);
76+
}
77+
}
78+
return NULL;
79+
}
80+
81+
if (zend_hash_add(stack, lname, &dummy) == NULL) {
82+
// Recursion protection
83+
return NULL;
84+
}
85+
86+
ZEND_HASH_FOREACH_PTR(&EG(autoload.functions), func_info)
87+
if (func_info->type & type) {
88+
func_info->fci.retval = &retval;
89+
zend_fcall_info_argn(&func_info->fci, 2, &zname, &ztype);
90+
zend_call_function(&func_info->fci, &func_info->fcc);
91+
zend_exception_save();
92+
if (zend_hash_exists(symbol_table, lname)) {
93+
break;
94+
}
95+
}
96+
ZEND_HASH_FOREACH_END();
97+
98+
zend_fcall_info_args_clear(&func_info->fci, 1);
99+
zend_exception_restore();
100+
101+
zend_hash_del(stack, lname);
102+
103+
return zend_hash_find_ptr(symbol_table, lname);
104+
}
105+
106+
static zend_string* zend_autoload_get_key(zend_fcall_info *fci)
107+
{
108+
switch (Z_TYPE(fci->function_name)) {
109+
case IS_STRING:
110+
return Z_STR(fci->function_name);
111+
case IS_OBJECT: {
112+
char handle[16];
113+
sprintf(handle, "%lu", (unsigned long) Z_OBJ_HANDLE(fci->function_name));
114+
return zend_string_init(handle, sizeof(uint32_t), 0);
115+
}
116+
}
117+
return NULL;
118+
}
119+
120+
121+
int zend_autoload_register(zend_autoload_func* func, zend_bool prepend)
122+
{
123+
zend_string *key;
124+
125+
key = zend_autoload_get_key(&func->fci);
126+
if (key == NULL) {
127+
zend_error_noreturn(E_ERROR, "Unknown function type provided");
128+
}
129+
130+
if (zend_hash_add_ptr(&EG(autoload.functions), key, func) == NULL) {
131+
return FAILURE;
132+
}
133+
134+
if (prepend) {
135+
HT_MOVE_TAIL_TO_HEAD(&EG(autoload.functions));
136+
}
137+
return SUCCESS;
138+
}
139+
140+
int zend_autoload_unregister(zend_autoload_func* func)
141+
{
142+
zend_string *key;
143+
144+
key = zend_autoload_get_key(&func->fci);
145+
146+
zend_hash_del(&EG(autoload.functions), key);
147+
148+
return SUCCESS;
149+
}
150+
151+
ZEND_FUNCTION(autoload_register)
152+
{
153+
zend_autoload_func *func;
154+
zend_bool prepend = 0;
155+
156+
func = emalloc(sizeof(zend_autoload_func));
157+
158+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f|lb", &func->fci, &func->fcc, &func->type, &prepend) == FAILURE) {
159+
efree(func);
160+
return;
161+
}
162+
163+
if (!func->type) {
164+
func->type = ZEND_AUTOLOAD_ALL;
165+
}
166+
167+
if (zend_autoload_register(func, prepend) == FAILURE) {
168+
RETURN_FALSE;
169+
}
170+
RETURN_TRUE;
171+
}
172+
173+
ZEND_FUNCTION(autoload_unregister)
174+
{
175+
zend_autoload_func *func;
176+
177+
func = emalloc(sizeof(zend_autoload_func));
178+
179+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f", &func->fci, &func->fcc) == FAILURE) {
180+
efree(func);
181+
return;
182+
}
183+
184+
if (zend_autoload_unregister(func) == FAILURE) {
185+
efree(func);
186+
RETURN_FALSE;
187+
}
188+
efree(func);
189+
RETURN_TRUE;
190+
}

Zend/zend_autoload.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Zend Engine |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 1998-2014 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+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Anthony Ferrara <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
/* $Id$ */
20+
21+
#include "zend.h"
22+
#include "zend_API.h"
23+
#include "zend_hash.h"
24+
25+
ZEND_FUNCTION(autoload_register);
26+
ZEND_FUNCTION(autoload_unregister);
27+
28+
typedef struct {
29+
zend_fcall_info fci;
30+
zend_fcall_info_cache fcc;
31+
zval *callable;
32+
long type;
33+
} zend_autoload_func;
34+
35+
void* zend_autoload_call(zend_string *name, zend_string *lname, long type);
36+
int zend_autoload_register(zend_autoload_func* func, zend_bool prepend);
37+
int zend_autoload_unregister(zend_autoload_func* func);
38+
39+
#define ZEND_AUTOLOAD_CLASS (1<<0)
40+
#define ZEND_AUTOLOAD_FUNCTION (1<<1)
41+
#define ZEND_AUTOLOAD_CONSTANT (1<<2)
42+
#define ZEND_AUTOLOAD_ALL (~0)

Zend/zend_builtin_functions.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "zend.h"
2323
#include "zend_API.h"
2424
#include "zend_builtin_functions.h"
25+
#include "zend_autoload.h"
2526
#include "zend_constants.h"
2627
#include "zend_ini.h"
2728
#include "zend_exceptions.h"
@@ -243,6 +244,16 @@ ZEND_END_ARG_INFO()
243244
ZEND_BEGIN_ARG_INFO_EX(arginfo_extension_loaded, 0, 0, 1)
244245
ZEND_ARG_INFO(0, extension_name)
245246
ZEND_END_ARG_INFO()
247+
248+
ZEND_BEGIN_ARG_INFO_EX(arginfo_autoload_register, 0, 0, 1)
249+
ZEND_ARG_INFO(0, callback)
250+
ZEND_ARG_INFO(0, type)
251+
ZEND_ARG_INFO(0, prepend)
252+
ZEND_END_ARG_INFO()
253+
254+
ZEND_BEGIN_ARG_INFO_EX(arginfo_autoload_unregister, 0, 0, 1)
255+
ZEND_ARG_INFO(0, callback)
256+
ZEND_END_ARG_INFO()
246257
/* }}} */
247258

248259
static const zend_function_entry builtin_functions[] = { /* {{{ */
@@ -313,6 +324,8 @@ static const zend_function_entry builtin_functions[] = { /* {{{ */
313324
ZEND_FE(gc_enabled, arginfo_zend__void)
314325
ZEND_FE(gc_enable, arginfo_zend__void)
315326
ZEND_FE(gc_disable, arginfo_zend__void)
327+
ZEND_NS_FE("php", autoload_register, arginfo_autoload_register)
328+
ZEND_NS_FE("php", autoload_unregister, arginfo_autoload_unregister)
316329
ZEND_FE_END
317330
};
318331
/* }}} */

Zend/zend_constants.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "zend_operators.h"
2727
#include "zend_globals.h"
2828
#include "zend_API.h"
29+
#include "zend_autoload.h"
2930

3031
void free_zend_constant(zval *zv)
3132
{
@@ -141,6 +142,12 @@ void zend_register_standard_constants(void)
141142
REGISTER_MAIN_BOOL_CONSTANT("ZEND_DEBUG_BUILD", ZEND_DEBUG, CONST_PERSISTENT | CONST_CS);
142143
}
143144
REGISTER_MAIN_NULL_CONSTANT("NULL", CONST_PERSISTENT | CONST_CT_SUBST);
145+
146+
REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_CLASS"), ZEND_AUTOLOAD_CLASS, CONST_CS | CONST_PERSISTENT);
147+
REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_FUNCTION"), ZEND_AUTOLOAD_FUNCTION, CONST_CS | CONST_PERSISTENT);
148+
REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_CONSTANT"), ZEND_AUTOLOAD_CONSTANT, CONST_CS | CONST_PERSISTENT);
149+
REGISTER_MAIN_LONG_CONSTANT(ZEND_NS_NAME("php", "AUTOLOAD_ALL"), ZEND_AUTOLOAD_ALL, CONST_CS | CONST_PERSISTENT);
150+
144151
}
145152

146153

Zend/zend_execute_API.c

Lines changed: 7 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "zend_generators.h"
3535
#include "zend_vm.h"
3636
#include "zend_float.h"
37+
#include "zend_autoload.h"
3738
#ifdef HAVE_SYS_TIME_H
3839
#include <sys/time.h>
3940
#endif
@@ -150,6 +151,11 @@ void init_executor(void) /* {{{ */
150151
EG(autoload_func) = NULL;
151152
EG(error_handling) = EH_NORMAL;
152153

154+
ZEND_INIT_SYMTABLE(&EG(autoload.stack.class));
155+
ZEND_INIT_SYMTABLE(&EG(autoload.stack.function));
156+
ZEND_INIT_SYMTABLE(&EG(autoload.stack.constant));
157+
ZEND_INIT_SYMTABLE(&EG(autoload.functions));
158+
153159
zend_vm_stack_init();
154160

155161
zend_hash_init(&EG(symbol_table).ht, 64, NULL, ZVAL_PTR_DTOR, 0);
@@ -957,77 +963,8 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *k
957963
return NULL;
958964
}
959965

960-
if (!EG(autoload_func)) {
961-
zend_function *func = zend_hash_str_find_ptr(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1);
962-
if (func) {
963-
EG(autoload_func) = func;
964-
} else {
965-
if (!key) {
966-
zend_string_free(lc_name);
967-
}
968-
return NULL;
969-
}
970-
971-
}
972-
973-
/* Verify class name before passing it to __autoload() */
974-
if (strspn(name->val, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\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\\") != name->len) {
975-
if (!key) {
976-
zend_string_free(lc_name);
977-
}
978-
return NULL;
979-
}
980-
981-
if (EG(in_autoload) == NULL) {
982-
ALLOC_HASHTABLE(EG(in_autoload));
983-
zend_hash_init(EG(in_autoload), 8, NULL, NULL, 0);
984-
}
985-
986-
if (zend_hash_add_empty_element(EG(in_autoload), lc_name) == NULL) {
987-
if (!key) {
988-
zend_string_free(lc_name);
989-
}
990-
return NULL;
991-
}
992-
993-
ZVAL_UNDEF(&local_retval);
994-
995-
if (name->val[0] == '\\') {
996-
ZVAL_STRINGL(&args[0], name->val + 1, name->len - 1);
997-
} else {
998-
ZVAL_STR_COPY(&args[0], name);
999-
}
1000-
1001-
fcall_info.size = sizeof(fcall_info);
1002-
fcall_info.function_table = EG(function_table);
1003-
ZVAL_STR_COPY(&fcall_info.function_name, EG(autoload_func)->common.function_name);
1004-
fcall_info.symbol_table = NULL;
1005-
fcall_info.retval = &local_retval;
1006-
fcall_info.param_count = 1;
1007-
fcall_info.params = args;
1008-
fcall_info.object = NULL;
1009-
fcall_info.no_separation = 1;
1010-
1011-
fcall_cache.initialized = 1;
1012-
fcall_cache.function_handler = EG(autoload_func);
1013-
fcall_cache.calling_scope = NULL;
1014-
fcall_cache.called_scope = NULL;
1015-
fcall_cache.object = NULL;
1016-
1017-
zend_exception_save();
1018-
retval = zend_call_function(&fcall_info, &fcall_cache);
1019-
zend_exception_restore();
966+
ce = (zend_class_entry*) zend_autoload_call(name, lc_name, ZEND_AUTOLOAD_CLASS);
1020967

1021-
zval_ptr_dtor(&args[0]);
1022-
zval_dtor(&fcall_info.function_name);
1023-
1024-
zend_hash_del(EG(in_autoload), lc_name);
1025-
1026-
zval_ptr_dtor(&local_retval);
1027-
1028-
if (retval == SUCCESS) {
1029-
ce = zend_hash_find_ptr(EG(class_table), lc_name);
1030-
}
1031968
if (!key) {
1032969
zend_string_free(lc_name);
1033970
}

0 commit comments

Comments
 (0)