Annotation of embedaddon/php/Zend/zend_closures.c, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | Zend Engine |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1998-2012 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: Christian Seiler <chris_se@gmx.net> |
16: | Dmitry Stogov <dmitry@zend.com> |
17: | Marcus Boerger <helly@php.net> |
18: +----------------------------------------------------------------------+
19: */
20:
21: /* $Id: zend_closures.c 321634 2012-01-01 13:15:04Z felipe $ */
22:
23: #include "zend.h"
24: #include "zend_API.h"
25: #include "zend_closures.h"
26: #include "zend_exceptions.h"
27: #include "zend_interfaces.h"
28: #include "zend_objects.h"
29: #include "zend_objects_API.h"
30: #include "zend_globals.h"
31:
32: #define ZEND_CLOSURE_PRINT_NAME "Closure object"
33:
34: #define ZEND_CLOSURE_PROPERTY_ERROR() \
35: zend_error(E_RECOVERABLE_ERROR, "Closure object cannot have properties")
36:
37: typedef struct _zend_closure {
38: zend_object std;
39: zend_function func;
40: HashTable *debug_info;
41: } zend_closure;
42:
43: /* non-static since it needs to be referenced */
44: ZEND_API zend_class_entry *zend_ce_closure;
45: static zend_object_handlers closure_handlers;
46:
47: ZEND_METHOD(Closure, __invoke) /* {{{ */
48: {
49: zend_function *func = EG(current_execute_data)->function_state.function;
50: zval ***arguments;
51: zval *closure_result_ptr = NULL;
52:
53: arguments = emalloc(sizeof(zval**) * ZEND_NUM_ARGS());
54: if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) {
55: efree(arguments);
56: zend_error(E_RECOVERABLE_ERROR, "Cannot get arguments for calling closure");
57: RETVAL_FALSE;
58: } else if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) {
59: RETVAL_FALSE;
60: } else if (closure_result_ptr) {
61: if (Z_ISREF_P(closure_result_ptr) && return_value_ptr) {
62: if (return_value) {
63: zval_ptr_dtor(&return_value);
64: }
65: *return_value_ptr = closure_result_ptr;
66: } else {
67: RETVAL_ZVAL(closure_result_ptr, 1, 1);
68: }
69: }
70: efree(arguments);
71:
72: /* destruct the function also, then - we have allocated it in get_method */
73: efree(func->internal_function.function_name);
74: efree(func);
75: }
76: /* }}} */
77:
78: static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */
79: {
80: zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
81: return NULL;
82: }
83: /* }}} */
84:
85: static int zend_closure_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
86: {
87: return (Z_OBJ_HANDLE_P(o1) != Z_OBJ_HANDLE_P(o2));
88: }
89: /* }}} */
90:
91: ZEND_API zend_function *zend_get_closure_invoke_method(zval *obj TSRMLS_DC) /* {{{ */
92: {
93: zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
94: zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));
95:
96: invoke->common = closure->func.common;
97: invoke->type = ZEND_INTERNAL_FUNCTION;
98: invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
99: invoke->internal_function.handler = ZEND_MN(Closure___invoke);
100: invoke->internal_function.module = 0;
101: invoke->internal_function.scope = zend_ce_closure;
102: invoke->internal_function.function_name = estrndup(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1);
103: return invoke;
104: }
105: /* }}} */
106:
107: ZEND_API const zend_function *zend_get_closure_method_def(zval *obj TSRMLS_DC) /* {{{ */
108: {
109: zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
110: return &closure->func;
111: }
112: /* }}} */
113:
114: static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */
115: {
116: char *lc_name;
117: ALLOCA_FLAG(use_heap)
118:
119: lc_name = do_alloca(method_len + 1, use_heap);
120: zend_str_tolower_copy(lc_name, method_name, method_len);
121: if ((method_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
122: memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
123: ) {
124: free_alloca(lc_name, use_heap);
125: return zend_get_closure_invoke_method(*object_ptr TSRMLS_CC);
126: }
127: free_alloca(lc_name, use_heap);
128: return NULL;
129: }
130: /* }}} */
131:
132: static zval *zend_closure_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
133: {
134: ZEND_CLOSURE_PROPERTY_ERROR();
135: Z_ADDREF(EG(uninitialized_zval));
136: return &EG(uninitialized_zval);
137: }
138: /* }}} */
139:
140: static void zend_closure_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
141: {
142: ZEND_CLOSURE_PROPERTY_ERROR();
143: }
144: /* }}} */
145:
146: static zval **zend_closure_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
147: {
148: ZEND_CLOSURE_PROPERTY_ERROR();
149: return NULL;
150: }
151: /* }}} */
152:
153: static int zend_closure_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
154: {
155: if (has_set_exists != 2) {
156: ZEND_CLOSURE_PROPERTY_ERROR();
157: }
158: return 0;
159: }
160: /* }}} */
161:
162: static void zend_closure_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
163: {
164: ZEND_CLOSURE_PROPERTY_ERROR();
165: }
166: /* }}} */
167:
168: static void zend_closure_free_storage(void *object TSRMLS_DC) /* {{{ */
169: {
170: zend_closure *closure = (zend_closure *)object;
171:
172: zend_object_std_dtor(&closure->std TSRMLS_CC);
173:
174: if (closure->func.type == ZEND_USER_FUNCTION) {
175: zend_execute_data *ex = EG(current_execute_data);
176: while (ex) {
177: if (ex->op_array == &closure->func.op_array) {
178: zend_error(E_ERROR, "Cannot destroy active lambda function");
179: }
180: ex = ex->prev_execute_data;
181: }
182: destroy_op_array(&closure->func.op_array TSRMLS_CC);
183: }
184:
185: if (closure->debug_info != NULL) {
186: zend_hash_destroy(closure->debug_info);
187: efree(closure->debug_info);
188: }
189:
190: efree(closure);
191: }
192: /* }}} */
193:
194: static zend_object_value zend_closure_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
195: {
196: zend_closure *closure;
197: zend_object_value object;
198:
199: closure = emalloc(sizeof(zend_closure));
200: memset(closure, 0, sizeof(zend_closure));
201:
202: zend_object_std_init(&closure->std, class_type TSRMLS_CC);
203:
204: object.handle = zend_objects_store_put(closure, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_closure_free_storage, NULL TSRMLS_CC);
205: object.handlers = &closure_handlers;
206:
207: return object;
208: }
209: /* }}} */
210:
211: int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
212: {
213: zend_closure *closure;
214:
215: if (Z_TYPE_P(obj) != IS_OBJECT) {
216: return FAILURE;
217: }
218:
219: closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
220: *fptr_ptr = &closure->func;
221:
222: if (zobj_ptr) {
223: *zobj_ptr = NULL;
224: }
225: *ce_ptr = NULL;
226: return SUCCESS;
227: }
228: /* }}} */
229:
230: static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
231: {
232: zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC);
233: zval *val;
234: struct _zend_arg_info *arg_info = closure->func.common.arg_info;
235:
236: *is_temp = 0;
237:
238: if (closure->debug_info == NULL) {
239: ALLOC_HASHTABLE(closure->debug_info);
240: zend_hash_init(closure->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0);
241: }
242: if (closure->debug_info->nApplyCount == 0) {
243: if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
244: HashTable *static_variables = closure->func.op_array.static_variables;
245: MAKE_STD_ZVAL(val);
246: array_init(val);
247: zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*));
248: zend_symtable_update(closure->debug_info, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL);
249: }
250:
251: if (arg_info) {
252: zend_uint i, required = closure->func.common.required_num_args;
253:
254: MAKE_STD_ZVAL(val);
255: array_init(val);
256:
257: for (i = 0; i < closure->func.common.num_args; i++) {
258: char *name, *info;
259: int name_len, info_len;
260: if (arg_info->name) {
261: name_len = zend_spprintf(&name, 0, "%s$%s",
262: arg_info->pass_by_reference ? "&" : "",
263: arg_info->name);
264: } else {
265: name_len = zend_spprintf(&name, 0, "%s$param%d",
266: arg_info->pass_by_reference ? "&" : "",
267: i + 1);
268: }
269: info_len = zend_spprintf(&info, 0, "%s",
270: i >= required ? "<optional>" : "<required>");
271: add_assoc_stringl_ex(val, name, name_len + 1, info, info_len, 0);
272: efree(name);
273: arg_info++;
274: }
275: zend_symtable_update(closure->debug_info, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL);
276: }
277: }
278:
279: return closure->debug_info;
280: }
281: /* }}} */
282:
283: static HashTable *zend_closure_get_properties(zval *obj TSRMLS_DC) /* {{{ */
284: {
285: zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
286:
287: if (GC_G(gc_active)) {
288: return (closure->func.type == ZEND_USER_FUNCTION) ? closure->func.op_array.static_variables : NULL;
289: }
290:
291: return closure->std.properties;
292: }
293: /* }}} */
294:
295: /* {{{ proto Closure::__construct()
296: Private constructor preventing instantiation */
297: ZEND_METHOD(Closure, __construct)
298: {
299: zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
300: }
301: /* }}} */
302:
303: static const zend_function_entry closure_functions[] = {
304: ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
305: {NULL, NULL, NULL}
306: };
307:
308: void zend_register_closure_ce(TSRMLS_D) /* {{{ */
309: {
310: zend_class_entry ce;
311:
312: INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
313: zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC);
314: zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS;
315: zend_ce_closure->create_object = zend_closure_new;
316: zend_ce_closure->serialize = zend_class_serialize_deny;
317: zend_ce_closure->unserialize = zend_class_unserialize_deny;
318:
319: memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
320: closure_handlers.get_constructor = zend_closure_get_constructor;
321: closure_handlers.get_method = zend_closure_get_method;
322: closure_handlers.write_property = zend_closure_write_property;
323: closure_handlers.read_property = zend_closure_read_property;
324: closure_handlers.get_property_ptr_ptr = zend_closure_get_property_ptr_ptr;
325: closure_handlers.has_property = zend_closure_has_property;
326: closure_handlers.unset_property = zend_closure_unset_property;
327: closure_handlers.compare_objects = zend_closure_compare_objects;
328: closure_handlers.clone_obj = NULL;
329: closure_handlers.get_debug_info = zend_closure_get_debug_info;
330: closure_handlers.get_closure = zend_closure_get_closure;
331: closure_handlers.get_properties = zend_closure_get_properties;
332: }
333: /* }}} */
334:
335: static int zval_copy_static_var(zval **p TSRMLS_DC, int num_args, va_list args, zend_hash_key *key) /* {{{ */
336: {
337: HashTable *target = va_arg(args, HashTable*);
338: zend_bool is_ref;
339: zval *tmp;
340:
341: if (Z_TYPE_PP(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) {
342: is_ref = Z_TYPE_PP(p) & IS_LEXICAL_REF;
343:
344: if (!EG(active_symbol_table)) {
345: zend_rebuild_symbol_table(TSRMLS_C);
346: }
347: if (zend_hash_quick_find(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, (void **) &p) == FAILURE) {
348: if (is_ref) {
349: ALLOC_INIT_ZVAL(tmp);
350: Z_SET_ISREF_P(tmp);
351: zend_hash_quick_add(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), (void**)&p);
352: } else {
353: tmp = EG(uninitialized_zval_ptr);
354: zend_error(E_NOTICE,"Undefined variable: %s", key->arKey);
355: }
356: } else {
357: if (is_ref) {
358: SEPARATE_ZVAL_TO_MAKE_IS_REF(p);
359: tmp = *p;
360: } else if (Z_ISREF_PP(p)) {
361: ALLOC_INIT_ZVAL(tmp);
362: *tmp = **p;
363: zval_copy_ctor(tmp);
364: Z_SET_REFCOUNT_P(tmp, 0);
365: Z_UNSET_ISREF_P(tmp);
366: } else {
367: tmp = *p;
368: }
369: }
370: } else {
371: tmp = *p;
372: }
373: if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), NULL) == SUCCESS) {
374: Z_ADDREF_P(tmp);
375: }
376: return ZEND_HASH_APPLY_KEEP;
377: }
378: /* }}} */
379:
380: ZEND_API void zend_create_closure(zval *res, zend_function *func TSRMLS_DC) /* {{{ */
381: {
382: zend_closure *closure;
383:
384: object_init_ex(res, zend_ce_closure);
385:
386: closure = (zend_closure *)zend_object_store_get_object(res TSRMLS_CC);
387:
388: closure->func = *func;
389: closure->func.common.prototype = NULL;
390:
391: if (closure->func.type == ZEND_USER_FUNCTION) {
392: if (closure->func.op_array.static_variables) {
393: HashTable *static_variables = closure->func.op_array.static_variables;
394:
395: ALLOC_HASHTABLE(closure->func.op_array.static_variables);
396: zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
397: zend_hash_apply_with_arguments(static_variables TSRMLS_CC, (apply_func_args_t)zval_copy_static_var, 1, closure->func.op_array.static_variables);
398: }
399: (*closure->func.op_array.refcount)++;
400: }
401:
402: closure->func.common.scope = NULL;
403: }
404: /* }}} */
405:
406: /*
407: * Local variables:
408: * tab-width: 4
409: * c-basic-offset: 4
410: * indent-tabs-mode: t
411: * End:
412: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>