Skip to content

Commit

Permalink
- Made closures implementation reflection friendly (Christian)
Browse files Browse the repository at this point in the history
- Changed E_ERROR(s) into E_RECOVERABLE_ERROR(s) (Marcus)
  • Loading branch information
dstogov committed Aug 11, 2008
1 parent 8526b78 commit a4a3ed4
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Zend/tests/closure_022.phpt
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ $foo = function() use ($a) {
$foo->a = 1; $foo->a = 1;
?> ?>
--EXPECTF-- --EXPECTF--
Fatal error: Closure object cannot have properties in %sclosure_022.php on line 5 Catchable fatal error: Closure object cannot have properties in %sclosure_022.php on line 5


43 changes: 25 additions & 18 deletions Zend/zend_closures.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@
#include "zend_objects_API.h" #include "zend_objects_API.h"
#include "zend_globals.h" #include "zend_globals.h"


#define ZEND_INVOKE_FUNC_NAME "__invoke"
#define ZEND_CLOSURE_PRINT_NAME "Closure object" #define ZEND_CLOSURE_PRINT_NAME "Closure object"


#define ZEND_CLOSURE_PROPERTY_ERROR() \ #define ZEND_CLOSURE_PROPERTY_ERROR() \
zend_error(E_ERROR, "Closure object cannot have properties") zend_error(E_RECOVERABLE_ERROR, "Closure object cannot have properties")


typedef struct _zend_closure { typedef struct _zend_closure {
zend_object std; zend_object std;
zend_function func; zend_function func;
zval *this_ptr; zval *this_ptr;
} zend_closure; } zend_closure;


static zend_class_entry *zend_ce_closure; /* non-static since it needs to be referenced */
ZEND_API zend_class_entry *zend_ce_closure;
static zend_object_handlers closure_handlers; static zend_object_handlers closure_handlers;


ZEND_METHOD(Closure, __invoke) /* {{{ */ ZEND_METHOD(Closure, __invoke) /* {{{ */
Expand All @@ -50,7 +50,7 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */
arguments = emalloc(sizeof(zval**) * ZEND_NUM_ARGS()); arguments = emalloc(sizeof(zval**) * ZEND_NUM_ARGS());
if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) { if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) {
efree(arguments); efree(arguments);
zend_error(E_ERROR, "Cannot get arguments for calling closure"); zend_error(E_RECOVERABLE_ERROR, "Cannot get arguments for calling closure");
RETVAL_FALSE; RETVAL_FALSE;
} else if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) { } else if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) {
RETVAL_FALSE; RETVAL_FALSE;
Expand All @@ -74,21 +74,21 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */


static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */ static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */
{ {
zend_error(E_ERROR, "Instantiation of 'Closure' is not allowed"); zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
return NULL; return NULL;
} }
/* }}} */ /* }}} */


static int zend_closure_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) /* {{{ */ static int zend_closure_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) /* {{{ */
{ {
zend_error(E_ERROR, "Serialization of 'Closure' is not allowed"); zend_error(E_RECOVERABLE_ERROR, "Serialization of 'Closure' is not allowed");
return FAILURE; return FAILURE;
} }
/* }}} */ /* }}} */


static int zend_closure_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC) /* {{{ */ static int zend_closure_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC) /* {{{ */
{ {
zend_error(E_ERROR, "Unserialization of 'Closure' is not allowed"); zend_error(E_RECOVERABLE_ERROR, "Unserialization of 'Closure' is not allowed");
return FAILURE; return FAILURE;
} }
/* }}} */ /* }}} */
Expand All @@ -99,6 +99,23 @@ static int zend_closure_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
} }
/* }}} */ /* }}} */


ZEND_API zend_function *zend_get_closure_invoke_method(zval *obj TSRMLS_DC) /* {{{ */
{
zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));

invoke->common = closure->func.common;
invoke->type = ZEND_INTERNAL_FUNCTION;
invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
invoke->internal_function.handler = ZEND_MN(Closure___invoke);
invoke->internal_function.module = 0;
invoke->internal_function.scope = zend_ce_closure;
invoke->internal_function.function_name = estrndup(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1);
return invoke;

}
/* }}} */

static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */ static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */
{ {
char *lc_name; char *lc_name;
Expand All @@ -109,18 +126,8 @@ static zend_function *zend_closure_get_method(zval **object_ptr, char *method_na
if ((method_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && if ((method_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
) { ) {
zend_closure *closure = (zend_closure *)zend_object_store_get_object(*object_ptr TSRMLS_CC);
zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));

invoke->common = closure->func.common;
invoke->type = ZEND_INTERNAL_FUNCTION;
invoke->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
invoke->internal_function.handler = ZEND_MN(Closure___invoke);
invoke->internal_function.module = 0;
invoke->internal_function.scope = zend_ce_closure;
invoke->internal_function.function_name = estrndup(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1);
free_alloca(lc_name, use_heap); free_alloca(lc_name, use_heap);
return invoke; return zend_get_closure_invoke_method(*object_ptr TSRMLS_CC);
} }
free_alloca(lc_name, use_heap); free_alloca(lc_name, use_heap);
return NULL; return NULL;
Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_closures.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@


BEGIN_EXTERN_C() BEGIN_EXTERN_C()


#define ZEND_INVOKE_FUNC_NAME "__invoke"

void zend_register_closure_ce(TSRMLS_D); void zend_register_closure_ce(TSRMLS_D);


extern ZEND_API zend_class_entry *zend_ce_closure;

ZEND_API void zend_create_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zval *this_ptr TSRMLS_DC); ZEND_API void zend_create_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zval *this_ptr TSRMLS_DC);
ZEND_API int zend_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr, zval ***zobj_ptr_ptr TSRMLS_DC); ZEND_API int zend_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr, zval ***zobj_ptr_ptr TSRMLS_DC);
ZEND_API zend_function *zend_get_closure_invoke_method(zval *obj TSRMLS_DC);


END_EXTERN_C() END_EXTERN_C()


Expand Down

0 comments on commit a4a3ed4

Please sign in to comment.