2008-07-14 17:49:03 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2012-01-01 21:15:04 +08:00
| Copyright ( c ) 1998 - 2012 Zend Technologies Ltd . ( http : //www.zend.com) |
2008-07-14 17:49:03 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| This source file is subject to version 2.00 of the Zend license , |
| that is bundled with this package in the file LICENSE , and is |
| available through the world - wide - web at the following url : |
| http : //www.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ zend . com so we can mail you a copy immediately . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Christian Seiler < chris_se @ gmx . net > |
| Dmitry Stogov < dmitry @ zend . com > |
2009-01-02 00:22:44 +08:00
| Marcus Boerger < helly @ php . net > |
2008-07-14 17:49:03 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
/* $Id$ */
# include "zend.h"
# include "zend_API.h"
# include "zend_closures.h"
2009-01-02 00:22:44 +08:00
# include "zend_exceptions.h"
2008-12-22 22:11:49 +08:00
# include "zend_interfaces.h"
2008-07-14 17:49:03 +08:00
# include "zend_objects.h"
# include "zend_objects_API.h"
# include "zend_globals.h"
# define ZEND_CLOSURE_PRINT_NAME "Closure object"
2008-07-22 15:29:31 +08:00
# define ZEND_CLOSURE_PROPERTY_ERROR() \
2008-08-11 16:49:00 +08:00
zend_error ( E_RECOVERABLE_ERROR , " Closure object cannot have properties " )
2008-07-22 15:29:31 +08:00
2008-07-14 17:49:03 +08:00
typedef struct _zend_closure {
zend_object std ;
zend_function func ;
2010-04-20 03:45:03 +08:00
zval * this_ptr ;
2009-08-10 23:18:13 +08:00
HashTable * debug_info ;
2008-07-14 17:49:03 +08:00
} zend_closure ;
2008-08-11 16:49:00 +08:00
/* non-static since it needs to be referenced */
ZEND_API zend_class_entry * zend_ce_closure ;
2008-07-14 17:49:03 +08:00
static zend_object_handlers closure_handlers ;
ZEND_METHOD ( Closure , __invoke ) /* {{{ */
{
2008-07-26 21:14:04 +08:00
zend_function * func = EG ( current_execute_data ) - > function_state . function ;
2008-07-14 17:49:03 +08:00
zval * * * arguments ;
zval * closure_result_ptr = NULL ;
arguments = emalloc ( sizeof ( zval * * ) * ZEND_NUM_ARGS ( ) ) ;
if ( zend_get_parameters_array_ex ( ZEND_NUM_ARGS ( ) , arguments ) = = FAILURE ) {
efree ( arguments ) ;
2008-08-11 16:49:00 +08:00
zend_error ( E_RECOVERABLE_ERROR , " Cannot get arguments for calling closure " ) ;
2008-07-26 21:14:04 +08:00
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 ) {
RETVAL_FALSE ;
} else if ( closure_result_ptr ) {
2008-07-14 17:49:03 +08:00
if ( Z_ISREF_P ( closure_result_ptr ) & & return_value_ptr ) {
if ( return_value ) {
zval_ptr_dtor ( & return_value ) ;
}
* return_value_ptr = closure_result_ptr ;
} else {
RETVAL_ZVAL ( closure_result_ptr , 1 , 1 ) ;
}
}
2008-07-26 21:14:04 +08:00
efree ( arguments ) ;
2008-07-14 17:49:03 +08:00
2008-07-26 21:14:04 +08:00
/* destruct the function also, then - we have allocated it in get_method */
2011-09-13 21:29:35 +08:00
efree ( ( char * ) func - > internal_function . function_name ) ;
2008-07-26 21:14:04 +08:00
efree ( func ) ;
}
2008-07-14 20:18:23 +08:00
/* }}} */
2011-09-07 14:46:27 +08:00
/* {{{ proto Closure Closure::bind(Closure $old, object $to [, mixed $scope = "static" ] )
Create a closure from another one and bind to another object and scope */
ZEND_METHOD ( Closure , bind ) /* {{{ */
2010-04-20 03:45:03 +08:00
{
2011-09-07 14:46:27 +08:00
zval * newthis , * zclosure , * scope_arg = NULL ;
zend_closure * closure ;
zend_class_entry * ce , * * ce_p ;
2010-04-20 03:45:03 +08:00
2011-09-07 14:46:27 +08:00
if ( zend_parse_method_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , getThis ( ) , " Oo!|z " , & zclosure , zend_ce_closure , & newthis , & scope_arg ) = = FAILURE ) {
2010-04-20 03:45:03 +08:00
RETURN_NULL ( ) ;
}
2011-09-07 14:46:27 +08:00
closure = ( zend_closure * ) zend_object_store_get_object ( zclosure TSRMLS_CC ) ;
2010-04-20 03:45:03 +08:00
2011-09-07 14:46:27 +08:00
if ( ( newthis ! = NULL ) & & ( closure - > func . common . fn_flags & ZEND_ACC_STATIC ) ) {
zend_error ( E_WARNING , " Cannot bind an instance to a static closure " ) ;
2010-04-20 03:45:03 +08:00
}
2011-09-07 14:46:27 +08:00
if ( scope_arg ! = NULL ) { /* scope argument was given */
if ( IS_ZEND_STD_OBJECT ( * scope_arg ) ) {
ce = Z_OBJCE_P ( scope_arg ) ;
} else if ( Z_TYPE_P ( scope_arg ) = = IS_NULL ) {
ce = NULL ;
} else {
char * class_name ;
int class_name_len ;
zval tmp_zval ;
INIT_ZVAL ( tmp_zval ) ;
if ( Z_TYPE_P ( scope_arg ) = = IS_STRING ) {
class_name = Z_STRVAL_P ( scope_arg ) ;
class_name_len = Z_STRLEN_P ( scope_arg ) ;
} else {
tmp_zval = * scope_arg ;
zval_copy_ctor ( & tmp_zval ) ;
convert_to_string ( & tmp_zval ) ;
class_name = Z_STRVAL ( tmp_zval ) ;
class_name_len = Z_STRLEN ( tmp_zval ) ;
}
if ( ( class_name_len = = sizeof ( " static " ) - 1 ) & &
( memcmp ( " static " , class_name , sizeof ( " static " ) - 1 ) = = 0 ) ) {
ce = closure - > func . common . scope ;
}
else if ( zend_lookup_class_ex ( class_name , class_name_len , NULL , 1 , & ce_p TSRMLS_CC ) = = FAILURE ) {
zend_error ( E_WARNING , " Class '%s' not found " , class_name ) ;
zval_dtor ( & tmp_zval ) ;
RETURN_NULL ( ) ;
} else {
ce = * ce_p ;
}
zval_dtor ( & tmp_zval ) ;
}
} else { /* scope argument not given; do not change the scope by default */
ce = closure - > func . common . scope ;
}
2010-04-20 03:45:03 +08:00
2011-09-07 14:46:27 +08:00
zend_create_closure ( return_value , & closure - > func , ce , newthis TSRMLS_CC ) ;
2010-04-20 03:45:03 +08:00
}
/* }}} */
2008-07-14 17:49:03 +08:00
static zend_function * zend_closure_get_constructor ( zval * object TSRMLS_DC ) /* { { { */
{
2008-08-11 16:49:00 +08:00
zend_error ( E_RECOVERABLE_ERROR , " Instantiation of 'Closure' is not allowed " ) ;
2008-07-14 17:49:03 +08:00
return NULL ;
}
/* }}} */
static int zend_closure_compare_objects ( zval * o1 , zval * o2 TSRMLS_DC ) /* { { { */
{
return ( Z_OBJ_HANDLE_P ( o1 ) ! = Z_OBJ_HANDLE_P ( o2 ) ) ;
}
/* }}} */
2008-08-11 16:49:00 +08:00
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 ;
2010-09-15 15:38:52 +08:00
invoke - > internal_function . fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | ( closure - > func . common . fn_flags & ZEND_ACC_RETURN_REFERENCE ) ;
2008-08-11 16:49:00 +08:00
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 ;
}
/* }}} */
2009-01-03 20:25:59 +08:00
ZEND_API const zend_function * zend_get_closure_method_def ( zval * obj TSRMLS_DC ) /* { { { */
{
zend_closure * closure = ( zend_closure * ) zend_object_store_get_object ( obj TSRMLS_CC ) ;
return & closure - > func ;
}
/* }}} */
2010-04-20 03:45:03 +08:00
ZEND_API zval * zend_get_closure_this_ptr ( zval * obj TSRMLS_DC ) /* { { { */
{
zend_closure * closure = ( zend_closure * ) zend_object_store_get_object ( obj TSRMLS_CC ) ;
return closure - > this_ptr ;
}
/* }}} */
2010-04-20 18:57:45 +08:00
static zend_function * zend_closure_get_method ( zval * * object_ptr , char * method_name , int method_len , const zend_literal * key TSRMLS_DC ) /* { { { */
2008-07-14 17:49:03 +08:00
{
char * lc_name ;
ALLOCA_FLAG ( use_heap )
lc_name = do_alloca ( method_len + 1 , use_heap ) ;
zend_str_tolower_copy ( lc_name , method_name , method_len ) ;
if ( ( method_len = = sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 ) & &
2008-07-22 15:44:41 +08:00
memcmp ( lc_name , ZEND_INVOKE_FUNC_NAME , sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 ) = = 0
) {
2008-07-14 17:49:03 +08:00
free_alloca ( lc_name , use_heap ) ;
2008-08-11 16:49:00 +08:00
return zend_get_closure_invoke_method ( * object_ptr TSRMLS_CC ) ;
2008-07-14 17:49:03 +08:00
}
free_alloca ( lc_name , use_heap ) ;
2010-04-20 18:57:45 +08:00
return std_object_handlers . get_method ( object_ptr , method_name , method_len , key TSRMLS_CC ) ;
2008-07-14 17:49:03 +08:00
}
/* }}} */
2010-04-20 18:57:45 +08:00
static zval * zend_closure_read_property ( zval * object , zval * member , int type , const zend_literal * key TSRMLS_DC ) /* { { { */
2008-07-22 15:29:31 +08:00
{
2008-07-22 15:44:41 +08:00
ZEND_CLOSURE_PROPERTY_ERROR ( ) ;
2008-09-17 21:08:54 +08:00
Z_ADDREF ( EG ( uninitialized_zval ) ) ;
return & EG ( uninitialized_zval ) ;
2008-07-22 15:29:31 +08:00
}
/* }}} */
2010-04-20 18:57:45 +08:00
static void zend_closure_write_property ( zval * object , zval * member , zval * value , const zend_literal * key TSRMLS_DC ) /* { { { */
2008-07-22 15:29:31 +08:00
{
2008-07-22 15:44:41 +08:00
ZEND_CLOSURE_PROPERTY_ERROR ( ) ;
2008-07-22 15:29:31 +08:00
}
/* }}} */
2010-04-20 18:57:45 +08:00
static zval * * zend_closure_get_property_ptr_ptr ( zval * object , zval * member , const zend_literal * key TSRMLS_DC ) /* { { { */
2008-07-22 15:29:31 +08:00
{
2008-07-22 15:44:41 +08:00
ZEND_CLOSURE_PROPERTY_ERROR ( ) ;
2008-07-22 15:29:31 +08:00
return NULL ;
}
/* }}} */
2010-04-20 18:57:45 +08:00
static int zend_closure_has_property ( zval * object , zval * member , int has_set_exists , const zend_literal * key TSRMLS_DC ) /* { { { */
2008-07-22 15:29:31 +08:00
{
2009-11-12 02:59:37 +08:00
if ( has_set_exists ! = 2 ) {
ZEND_CLOSURE_PROPERTY_ERROR ( ) ;
}
2008-07-22 15:29:31 +08:00
return 0 ;
}
/* }}} */
2010-04-20 18:57:45 +08:00
static void zend_closure_unset_property ( zval * object , zval * member , const zend_literal * key TSRMLS_DC ) /* { { { */
2008-07-22 15:29:31 +08:00
{
2008-07-22 15:44:41 +08:00
ZEND_CLOSURE_PROPERTY_ERROR ( ) ;
2008-07-22 15:29:31 +08:00
}
/* }}} */
2008-07-14 17:49:03 +08:00
static void zend_closure_free_storage ( void * object TSRMLS_DC ) /* { { { */
{
zend_closure * closure = ( zend_closure * ) object ;
zend_object_std_dtor ( & closure - > std TSRMLS_CC ) ;
if ( closure - > func . type = = ZEND_USER_FUNCTION ) {
zend_execute_data * ex = EG ( current_execute_data ) ;
while ( ex ) {
if ( ex - > op_array = = & closure - > func . op_array ) {
zend_error ( E_ERROR , " Cannot destroy active lambda function " ) ;
}
ex = ex - > prev_execute_data ;
}
destroy_op_array ( & closure - > func . op_array TSRMLS_CC ) ;
}
2009-08-10 23:18:13 +08:00
if ( closure - > debug_info ! = NULL ) {
zend_hash_destroy ( closure - > debug_info ) ;
efree ( closure - > debug_info ) ;
}
2010-04-20 03:45:03 +08:00
if ( closure - > this_ptr ) {
zval_ptr_dtor ( & closure - > this_ptr ) ;
}
2008-07-14 17:49:03 +08:00
efree ( closure ) ;
}
/* }}} */
static zend_object_value zend_closure_new ( zend_class_entry * class_type TSRMLS_DC ) /* { { { */
{
zend_closure * closure ;
zend_object_value object ;
closure = emalloc ( sizeof ( zend_closure ) ) ;
memset ( closure , 0 , sizeof ( zend_closure ) ) ;
zend_object_std_init ( & closure - > std , class_type TSRMLS_CC ) ;
2008-07-22 15:44:41 +08:00
2008-07-14 17:49:03 +08:00
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 ) ;
object . handlers = & closure_handlers ;
2008-07-22 15:44:41 +08:00
2008-07-14 17:49:03 +08:00
return object ;
}
/* }}} */
2010-04-20 03:45:03 +08:00
static zend_object_value zend_closure_clone ( zval * zobject TSRMLS_DC ) /* { { { */
{
zend_closure * closure = ( zend_closure * ) zend_object_store_get_object ( zobject TSRMLS_CC ) ;
zval result ;
2010-04-20 20:53:43 +08:00
zend_create_closure ( & result , & closure - > func , closure - > func . common . scope , closure - > this_ptr TSRMLS_CC ) ;
2010-04-20 03:45:03 +08:00
return Z_OBJVAL ( result ) ;
}
/* }}} */
2008-11-28 03:01:23 +08:00
int zend_closure_get_closure ( zval * obj , zend_class_entry * * ce_ptr , zend_function * * fptr_ptr , zval * * zobj_ptr TSRMLS_DC ) /* { { { */
2008-08-15 05:36:56 +08:00
{
zend_closure * closure ;
if ( Z_TYPE_P ( obj ) ! = IS_OBJECT ) {
return FAILURE ;
}
closure = ( zend_closure * ) zend_object_store_get_object ( obj TSRMLS_CC ) ;
* fptr_ptr = & closure - > func ;
2010-04-20 03:45:03 +08:00
if ( closure - > this_ptr ) {
if ( zobj_ptr ) {
* zobj_ptr = closure - > this_ptr ;
}
* ce_ptr = Z_OBJCE_P ( closure - > this_ptr ) ;
} else {
if ( zobj_ptr ) {
* zobj_ptr = NULL ;
}
* ce_ptr = closure - > func . common . scope ;
2008-08-15 05:36:56 +08:00
}
return SUCCESS ;
}
/* }}} */
2009-01-04 01:48:40 +08:00
static HashTable * zend_closure_get_debug_info ( zval * object , int * is_temp TSRMLS_DC ) /* { { { */
2009-01-02 00:22:44 +08:00
{
zend_closure * closure = ( zend_closure * ) zend_object_store_get_object ( object TSRMLS_CC ) ;
zval * val ;
struct _zend_arg_info * arg_info = closure - > func . common . arg_info ;
2009-08-10 23:18:13 +08:00
* is_temp = 0 ;
if ( closure - > debug_info = = NULL ) {
ALLOC_HASHTABLE ( closure - > debug_info ) ;
zend_hash_init ( closure - > debug_info , 1 , NULL , ZVAL_PTR_DTOR , 0 ) ;
2009-01-02 00:22:44 +08:00
}
2009-08-10 23:18:13 +08:00
if ( closure - > debug_info - > nApplyCount = = 0 ) {
if ( closure - > func . type = = ZEND_USER_FUNCTION & & closure - > func . op_array . static_variables ) {
HashTable * static_variables = closure - > func . op_array . static_variables ;
MAKE_STD_ZVAL ( val ) ;
array_init ( val ) ;
zend_hash_copy ( Z_ARRVAL_P ( val ) , static_variables , ( copy_ctor_func_t ) zval_add_ref , NULL , sizeof ( zval * ) ) ;
2010-04-20 18:57:45 +08:00
zend_hash_update ( closure - > debug_info , " static " , sizeof ( " static " ) , ( void * ) & val , sizeof ( zval * ) , NULL ) ;
2009-08-10 23:18:13 +08:00
}
2009-01-02 00:22:44 +08:00
2010-04-20 03:45:03 +08:00
if ( closure - > this_ptr ) {
Z_ADDREF_P ( closure - > this_ptr ) ;
zend_symtable_update ( closure - > debug_info , " this " , sizeof ( " this " ) , ( void * ) & closure - > this_ptr , sizeof ( zval * ) , NULL ) ;
}
2009-08-10 23:18:13 +08:00
if ( arg_info ) {
zend_uint i , required = closure - > func . common . required_num_args ;
MAKE_STD_ZVAL ( val ) ;
array_init ( val ) ;
for ( i = 0 ; i < closure - > func . common . num_args ; i + + ) {
char * name , * info ;
int name_len , info_len ;
if ( arg_info - > name ) {
name_len = zend_spprintf ( & name , 0 , " %s$%s " ,
arg_info - > pass_by_reference ? " & " : " " ,
arg_info - > name ) ;
} else {
name_len = zend_spprintf ( & name , 0 , " %s$param%d " ,
arg_info - > pass_by_reference ? " & " : " " ,
i + 1 ) ;
}
info_len = zend_spprintf ( & info , 0 , " %s " ,
i > = required ? " <optional> " : " <required> " ) ;
add_assoc_stringl_ex ( val , name , name_len + 1 , info , info_len , 0 ) ;
efree ( name ) ;
arg_info + + ;
2009-01-02 00:22:44 +08:00
}
2010-04-20 18:57:45 +08:00
zend_hash_update ( closure - > debug_info , " parameter " , sizeof ( " parameter " ) , ( void * ) & val , sizeof ( zval * ) , NULL ) ;
2009-01-02 00:22:44 +08:00
}
}
2009-08-10 23:18:13 +08:00
return closure - > debug_info ;
2009-01-02 00:22:44 +08:00
}
/* }}} */
2011-11-02 14:31:33 +08:00
static HashTable * zend_closure_get_gc ( zval * obj , zval * * * table , int * n TSRMLS_DC ) /* { { { */
{
zend_closure * closure = ( zend_closure * ) zend_object_store_get_object ( obj TSRMLS_CC ) ;
* table = closure - > this_ptr ? & closure - > this_ptr : NULL ;
* n = closure - > this_ptr ? 1 : 0 ;
return ( closure - > func . type = = ZEND_USER_FUNCTION ) ?
closure - > func . op_array . static_variables : NULL ;
}
/* }}} */
2009-01-04 03:29:55 +08:00
/* {{{ proto Closure::__construct()
Private constructor preventing instantiation */
ZEND_METHOD ( Closure , __construct )
{
zend_error ( E_RECOVERABLE_ERROR , " Instantiation of 'Closure' is not allowed " ) ;
}
/* }}} */
2011-09-07 14:46:27 +08:00
ZEND_BEGIN_ARG_INFO_EX ( arginfo_closure_bindto , 0 , 0 , 1 )
2010-04-20 03:45:03 +08:00
ZEND_ARG_INFO ( 0 , newthis )
2011-09-07 14:46:27 +08:00
ZEND_ARG_INFO ( 0 , newscope )
2010-04-20 03:45:03 +08:00
ZEND_END_ARG_INFO ( )
2011-09-07 14:46:27 +08:00
ZEND_BEGIN_ARG_INFO_EX ( arginfo_closure_bind , 0 , 0 , 2 )
2010-04-20 03:45:03 +08:00
ZEND_ARG_INFO ( 0 , closure )
2011-09-07 14:46:27 +08:00
ZEND_ARG_INFO ( 0 , newthis )
ZEND_ARG_INFO ( 0 , newscope )
2010-04-20 03:45:03 +08:00
ZEND_END_ARG_INFO ( )
2009-01-04 03:29:55 +08:00
static const zend_function_entry closure_functions [ ] = {
ZEND_ME ( Closure , __construct , NULL , ZEND_ACC_PRIVATE )
2010-04-20 03:45:03 +08:00
ZEND_ME ( Closure , bind , arginfo_closure_bind , ZEND_ACC_PUBLIC | ZEND_ACC_STATIC )
2011-09-07 14:46:27 +08:00
ZEND_MALIAS ( Closure , bindTo , bind , arginfo_closure_bindto , ZEND_ACC_PUBLIC )
2009-01-04 03:29:55 +08:00
{ NULL , NULL , NULL }
} ;
2008-07-14 17:49:03 +08:00
void zend_register_closure_ce ( TSRMLS_D ) /* { { { */
{
zend_class_entry ce ;
2009-01-04 03:29:55 +08:00
INIT_CLASS_ENTRY ( ce , " Closure " , closure_functions ) ;
2008-07-14 17:49:03 +08:00
zend_ce_closure = zend_register_internal_class ( & ce TSRMLS_CC ) ;
zend_ce_closure - > ce_flags | = ZEND_ACC_FINAL_CLASS ;
zend_ce_closure - > create_object = zend_closure_new ;
2008-12-22 22:11:49 +08:00
zend_ce_closure - > serialize = zend_class_serialize_deny ;
zend_ce_closure - > unserialize = zend_class_unserialize_deny ;
2008-07-14 17:49:03 +08:00
memcpy ( & closure_handlers , zend_get_std_object_handlers ( ) , sizeof ( zend_object_handlers ) ) ;
closure_handlers . get_constructor = zend_closure_get_constructor ;
closure_handlers . get_method = zend_closure_get_method ;
2008-07-22 15:29:31 +08:00
closure_handlers . write_property = zend_closure_write_property ;
closure_handlers . read_property = zend_closure_read_property ;
closure_handlers . get_property_ptr_ptr = zend_closure_get_property_ptr_ptr ;
closure_handlers . has_property = zend_closure_has_property ;
closure_handlers . unset_property = zend_closure_unset_property ;
2008-07-14 17:49:03 +08:00
closure_handlers . compare_objects = zend_closure_compare_objects ;
2010-04-20 03:45:03 +08:00
closure_handlers . clone_obj = zend_closure_clone ;
2009-01-02 00:22:44 +08:00
closure_handlers . get_debug_info = zend_closure_get_debug_info ;
2008-08-15 05:36:56 +08:00
closure_handlers . get_closure = zend_closure_get_closure ;
2011-11-02 14:31:33 +08:00
closure_handlers . get_gc = zend_closure_get_gc ;
2008-07-14 17:49:03 +08:00
}
/* }}} */
2010-04-20 03:45:03 +08:00
ZEND_API void zend_create_closure ( zval * res , zend_function * func , zend_class_entry * scope , zval * this_ptr TSRMLS_DC ) /* { { { */
2008-07-14 17:49:03 +08:00
{
zend_closure * closure ;
object_init_ex ( res , zend_ce_closure ) ;
closure = ( zend_closure * ) zend_object_store_get_object ( res TSRMLS_CC ) ;
closure - > func = * func ;
2011-04-20 20:59:18 +08:00
closure - > func . common . prototype = NULL ;
2008-07-14 17:49:03 +08:00
2011-09-07 14:46:27 +08:00
if ( ( scope = = NULL ) & & ( this_ptr ! = NULL ) ) {
/* use dummy scope if we're binding an object without specifying a scope */
/* maybe it would be better to create one for this purpose */
scope = zend_ce_closure ;
}
2008-07-14 17:49:03 +08:00
if ( closure - > func . type = = ZEND_USER_FUNCTION ) {
if ( closure - > func . op_array . static_variables ) {
HashTable * static_variables = closure - > func . op_array . static_variables ;
2008-07-22 15:44:41 +08:00
2008-07-14 17:49:03 +08:00
ALLOC_HASHTABLE ( closure - > func . op_array . static_variables ) ;
zend_hash_init ( closure - > func . op_array . static_variables , zend_hash_num_elements ( static_variables ) , NULL , ZVAL_PTR_DTOR , 0 ) ;
2008-07-25 03:52:24 +08:00
zend_hash_apply_with_arguments ( static_variables TSRMLS_CC , ( apply_func_args_t ) zval_copy_static_var , 1 , closure - > func . op_array . static_variables ) ;
2008-07-14 17:49:03 +08:00
}
2010-08-08 23:06:14 +08:00
closure - > func . op_array . run_time_cache = NULL ;
2008-07-14 17:49:03 +08:00
( * closure - > func . op_array . refcount ) + + ;
2010-04-20 03:45:03 +08:00
} else {
/* verify that we aren't binding internal function to a wrong scope */
if ( func - > common . scope ! = NULL ) {
if ( scope & & ! instanceof_function ( scope , func - > common . scope TSRMLS_CC ) ) {
zend_error ( E_WARNING , " Cannot bind function %s::%s to scope class %s " , func - > common . scope - > name , func - > common . function_name , scope - > name ) ;
scope = NULL ;
}
if ( scope & & this_ptr & & ( func - > common . fn_flags & ZEND_ACC_STATIC ) = = 0 & &
! instanceof_function ( Z_OBJCE_P ( this_ptr ) , closure - > func . common . scope TSRMLS_CC ) ) {
zend_error ( E_WARNING , " Cannot bind function %s::%s to object of class %s " , func - > common . scope - > name , func - > common . function_name , Z_OBJCE_P ( this_ptr ) - > name ) ;
scope = NULL ;
this_ptr = NULL ;
}
} else {
/* if it's a free function, we won't set scope & this since they're meaningless */
this_ptr = NULL ;
scope = NULL ;
}
2008-07-14 17:49:03 +08:00
}
2011-09-07 14:46:27 +08:00
/* Invariants:
* If the closure is unscoped , it has no bound object .
* The the closure is scoped , it ' s either static or it ' s bound */
2010-04-20 03:45:03 +08:00
closure - > func . common . scope = scope ;
if ( scope ) {
closure - > func . common . fn_flags | = ZEND_ACC_PUBLIC ;
if ( this_ptr & & ( closure - > func . common . fn_flags & ZEND_ACC_STATIC ) = = 0 ) {
closure - > this_ptr = this_ptr ;
Z_ADDREF_P ( this_ptr ) ;
} else {
closure - > func . common . fn_flags | = ZEND_ACC_STATIC ;
closure - > this_ptr = NULL ;
}
} else {
closure - > this_ptr = NULL ;
}
2008-07-14 17:49:03 +08:00
}
/* }}} */
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* indent - tabs - mode : t
* End :
*/