2008-07-14 17:49:03 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2014-01-03 11:08:10 +08:00
| Copyright ( c ) 1998 - 2014 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 , |
2013-02-19 12:56:02 +08:00
| that is bundled with this package in the file LICENSE , and is |
2008-07-14 17:49:03 +08:00
| 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 ;
2014-02-10 14:04:30 +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 ) /* {{{ */
{
2014-06-24 06:17:16 +08:00
zend_function * func = EG ( current_execute_data ) - > call - > func ;
2014-02-10 14:04:30 +08:00
zval * arguments ;
2008-07-14 17:49:03 +08:00
2014-02-10 14:04:30 +08:00
arguments = emalloc ( sizeof ( zval ) * ZEND_NUM_ARGS ( ) ) ;
2008-07-14 17:49:03 +08:00
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 ;
2014-03-28 06:11:22 +08:00
} else if ( call_user_function_ex ( CG ( function_table ) , NULL , getThis ( ) , return_value , ZEND_NUM_ARGS ( ) , arguments , 1 , NULL TSRMLS_CC ) = = FAILURE ) {
2008-07-26 21:14:04 +08:00
RETVAL_FALSE ;
2008-07-14 17:49:03 +08:00
}
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 */
2014-02-10 14:04:30 +08:00
STR_RELEASE ( 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 */
2012-09-02 16:52:53 +08:00
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 ;
2014-02-10 14:04:30 +08:00
zend_class_entry * ce ;
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 ( ) ;
}
2014-02-10 14:04:30 +08:00
closure = ( zend_closure * ) Z_OBJ_P ( zclosure ) ;
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 {
2014-04-22 02:36:01 +08:00
zend_string * class_name = zval_get_string ( scope_arg ) ;
2014-02-10 14:04:30 +08:00
if ( ( class_name - > len = = sizeof ( " static " ) - 1 ) & &
( memcmp ( " static " , class_name - > val , sizeof ( " static " ) - 1 ) = = 0 ) ) {
2011-09-07 14:46:27 +08:00
ce = closure - > func . common . scope ;
2014-04-16 00:33:38 +08:00
} else if ( ( ce = zend_lookup_class_ex ( class_name , NULL , 1 TSRMLS_CC ) ) = = NULL ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_WARNING , " Class '%s' not found " , class_name - > val ) ;
2014-04-16 00:33:38 +08:00
STR_RELEASE ( class_name ) ;
2011-09-07 14:46:27 +08:00
RETURN_NULL ( ) ;
}
2014-04-16 00:33:38 +08:00
STR_RELEASE ( class_name ) ;
2011-09-07 14:46:27 +08:00
}
} 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
}
/* }}} */
2014-03-28 06:11:22 +08:00
static zend_function * zend_closure_get_constructor ( zend_object * object TSRMLS_DC ) /* { { { */
2008-07-14 17:49:03 +08:00
{
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 ) /* { { { */
{
2014-02-10 14:04:30 +08:00
return ( Z_OBJ_P ( o1 ) ! = Z_OBJ_P ( o2 ) ) ;
2008-07-14 17:49:03 +08:00
}
/* }}} */
2014-03-28 06:11:22 +08:00
ZEND_API zend_function * zend_get_closure_invoke_method ( zend_object * object TSRMLS_DC ) /* { { { */
2008-08-11 16:49:00 +08:00
{
2014-03-28 06:11:22 +08:00
zend_closure * closure = ( zend_closure * ) object ;
2008-08-11 16:49:00 +08:00
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 ;
2014-02-10 14:04:30 +08:00
invoke - > internal_function . function_name = STR_INIT ( ZEND_INVOKE_FUNC_NAME , sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 , 0 ) ;
2008-08-11 16:49:00 +08:00
return invoke ;
}
/* }}} */
2009-01-03 20:25:59 +08:00
ZEND_API const zend_function * zend_get_closure_method_def ( zval * obj TSRMLS_DC ) /* { { { */
{
2014-02-10 14:04:30 +08:00
zend_closure * closure = ( zend_closure * ) Z_OBJ_P ( obj ) ;
2009-01-03 20:25:59 +08:00
return & closure - > func ;
}
/* }}} */
2010-04-20 03:45:03 +08:00
ZEND_API zval * zend_get_closure_this_ptr ( zval * obj TSRMLS_DC ) /* { { { */
{
2014-02-10 14:04:30 +08:00
zend_closure * closure = ( zend_closure * ) Z_OBJ_P ( obj ) ;
return & closure - > this_ptr ;
2010-04-20 03:45:03 +08:00
}
/* }}} */
2014-04-17 19:40:45 +08:00
static zend_function * zend_closure_get_method ( zend_object * * object , zend_string * method , const zval * key TSRMLS_DC ) /* { { { */
2008-07-14 17:49:03 +08:00
{
2014-02-10 14:04:30 +08:00
zend_string * lc_name ;
2008-07-14 17:49:03 +08:00
2014-02-10 14:04:30 +08:00
lc_name = STR_ALLOC ( method - > len , 0 ) ;
zend_str_tolower_copy ( lc_name - > val , method - > val , method - > len ) ;
if ( ( method - > len = = sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 ) & &
2014-02-25 17:47:33 +08:00
memcmp ( lc_name - > val , ZEND_INVOKE_FUNC_NAME , sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 ) = = 0
2008-07-22 15:44:41 +08:00
) {
2014-02-10 14:04:30 +08:00
STR_FREE ( lc_name ) ;
2014-03-28 06:11:22 +08:00
return zend_get_closure_invoke_method ( * object TSRMLS_CC ) ;
2008-07-14 17:49:03 +08:00
}
2014-02-10 14:04:30 +08:00
STR_FREE ( lc_name ) ;
2014-03-28 06:11:22 +08:00
return std_object_handlers . get_method ( object , method , key TSRMLS_CC ) ;
2008-07-14 17:49:03 +08:00
}
/* }}} */
2014-04-17 19:40:45 +08:00
static zval * zend_closure_read_property ( zval * object , zval * member , int type , zend_uint cache_slot , zval * rv 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
return & EG ( uninitialized_zval ) ;
2008-07-22 15:29:31 +08:00
}
/* }}} */
2014-04-17 19:40:45 +08:00
static void zend_closure_write_property ( zval * object , zval * member , zval * value , zend_uint cache_slot 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
}
/* }}} */
2014-04-17 19:40:45 +08:00
static zval * zend_closure_get_property_ptr_ptr ( zval * object , zval * member , int type , zend_uint cache_slot 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 ;
}
/* }}} */
2014-04-17 19:40:45 +08:00
static int zend_closure_has_property ( zval * object , zval * member , int has_set_exists , zend_uint cache_slot 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 ;
}
/* }}} */
2014-04-17 19:40:45 +08:00
static void zend_closure_unset_property ( zval * object , zval * member , zend_uint cache_slot 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
}
/* }}} */
2014-02-10 14:04:30 +08:00
static void zend_closure_free_storage ( zend_object * object TSRMLS_DC ) /* { { { */
2008-07-14 17:49:03 +08:00
{
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 ) ;
}
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( closure - > this_ptr ) ! = IS_UNDEF ) {
2010-04-20 03:45:03 +08:00
zval_ptr_dtor ( & closure - > this_ptr ) ;
}
2008-07-14 17:49:03 +08:00
}
/* }}} */
2014-02-10 14:04:30 +08:00
static zend_object * zend_closure_new ( zend_class_entry * class_type TSRMLS_DC ) /* { { { */
2008-07-14 17:49:03 +08:00
{
zend_closure * closure ;
closure = emalloc ( sizeof ( zend_closure ) ) ;
memset ( closure , 0 , sizeof ( zend_closure ) ) ;
zend_object_std_init ( & closure - > std , class_type TSRMLS_CC ) ;
2014-02-10 14:04:30 +08:00
closure - > std . handlers = & closure_handlers ;
2008-07-22 15:44:41 +08:00
2014-02-10 14:04:30 +08:00
return ( zend_object * ) closure ;
2008-07-14 17:49:03 +08:00
}
/* }}} */
2014-02-10 14:04:30 +08:00
static zend_object * zend_closure_clone ( zval * zobject TSRMLS_DC ) /* { { { */
2010-04-20 03:45:03 +08:00
{
2014-02-10 14:04:30 +08:00
zend_closure * closure = ( zend_closure * ) Z_OBJ_P ( zobject ) ;
2010-04-20 03:45:03 +08:00
zval result ;
2014-02-10 14:04:30 +08:00
zend_create_closure ( & result , & closure - > func , closure - > func . common . scope , & closure - > this_ptr TSRMLS_CC ) ;
return Z_OBJ ( result ) ;
2010-04-20 03:45:03 +08:00
}
/* }}} */
2014-03-28 06:11:22 +08:00
int zend_closure_get_closure ( zval * obj , zend_class_entry * * ce_ptr , zend_function * * fptr_ptr , zend_object * * obj_ptr TSRMLS_DC ) /* { { { */
2008-08-15 05:36:56 +08:00
{
zend_closure * closure ;
if ( Z_TYPE_P ( obj ) ! = IS_OBJECT ) {
return FAILURE ;
}
2014-02-10 14:04:30 +08:00
closure = ( zend_closure * ) Z_OBJ_P ( obj ) ;
2008-08-15 05:36:56 +08:00
* fptr_ptr = & closure - > func ;
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( closure - > this_ptr ) ! = IS_UNDEF ) {
2014-03-28 06:11:22 +08:00
if ( obj_ptr ) {
* obj_ptr = Z_OBJ ( closure - > this_ptr ) ;
2010-04-20 03:45:03 +08:00
}
2014-02-10 14:04:30 +08:00
* ce_ptr = Z_OBJCE ( closure - > this_ptr ) ;
2010-04-20 03:45:03 +08:00
} else {
2014-03-28 06:11:22 +08:00
if ( obj_ptr ) {
* obj_ptr = NULL ;
2010-04-20 03:45:03 +08:00
}
* 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
{
2014-02-10 14:04:30 +08:00
zend_closure * closure = ( zend_closure * ) Z_OBJ_P ( object ) ;
zval val ;
2009-01-02 00:22:44 +08:00
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 ) ;
2014-04-21 22:25:34 +08:00
zend_hash_init ( closure - > debug_info , 8 , NULL , ZVAL_PTR_DTOR , 0 ) ;
2009-01-02 00:22:44 +08:00
}
2014-04-21 22:25:34 +08:00
if ( closure - > debug_info - > u . v . nApplyCount = = 0 ) {
2009-08-10 23:18:13 +08:00
if ( closure - > func . type = = ZEND_USER_FUNCTION & & closure - > func . op_array . static_variables ) {
HashTable * static_variables = closure - > func . op_array . static_variables ;
2014-05-24 00:37:53 +08:00
ZVAL_NEW_ARR ( & val ) ;
zend_array_dup ( Z_ARRVAL ( val ) , static_variables ) ;
2014-02-10 14:04:30 +08:00
zend_hash_str_update ( closure - > debug_info , " static " , sizeof ( " static " ) - 1 , & val ) ;
2009-08-10 23:18:13 +08:00
}
2009-01-02 00:22:44 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_TYPE ( closure - > this_ptr ) ! = IS_UNDEF ) {
Z_ADDREF ( closure - > this_ptr ) ;
zend_hash_str_update ( closure - > debug_info , " this " , sizeof ( " this " ) - 1 , & closure - > this_ptr ) ;
2010-04-20 03:45:03 +08:00
}
2009-08-10 23:18:13 +08:00
if ( arg_info ) {
zend_uint i , required = closure - > func . common . required_num_args ;
2014-02-10 14:04:30 +08:00
array_init ( & val ) ;
2009-08-10 23:18:13 +08:00
for ( i = 0 ; i < closure - > func . common . num_args ; i + + ) {
2014-05-10 00:21:49 +08:00
zend_string * name ;
zval info ;
2009-08-10 23:18:13 +08:00
if ( arg_info - > name ) {
2014-05-10 00:21:49 +08:00
name = zend_strpprintf ( 0 , " %s$%s " ,
arg_info - > pass_by_reference ? " & " : " " ,
arg_info - > name ) ;
2009-08-10 23:18:13 +08:00
} else {
2014-05-10 00:21:49 +08:00
name = zend_strpprintf ( 0 , " %s$param%d " ,
arg_info - > pass_by_reference ? " & " : " " ,
i + 1 ) ;
2009-08-10 23:18:13 +08:00
}
2014-05-10 00:21:49 +08:00
ZVAL_STR ( & info , zend_strpprintf ( 0 , " %s " , i > = required ? " <optional> " : " <required> " ) ) ;
zend_hash_update ( Z_ARRVAL ( val ) , name , & info ) ;
STR_RELEASE ( name ) ;
2009-08-10 23:18:13 +08:00
arg_info + + ;
2009-01-02 00:22:44 +08:00
}
2014-02-10 14:04:30 +08:00
zend_hash_str_update ( closure - > debug_info , " parameter " , sizeof ( " parameter " ) - 1 , & val ) ;
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
}
/* }}} */
2014-02-10 14:04:30 +08:00
static HashTable * zend_closure_get_gc ( zval * obj , zval * * table , int * n TSRMLS_DC ) /* { { { */
2011-11-02 14:31:33 +08:00
{
2014-02-10 14:04:30 +08:00
zend_closure * closure = ( zend_closure * ) Z_OBJ_P ( obj ) ;
2011-11-02 14:31:33 +08:00
2014-03-22 01:35:47 +08:00
if ( closure - > debug_info ! = NULL ) {
zend_hash_destroy ( closure - > debug_info ) ;
efree ( closure - > debug_info ) ;
closure - > debug_info = NULL ;
}
2014-02-10 14:04:30 +08:00
* table = Z_TYPE ( closure - > this_ptr ) ! = IS_NULL ? & closure - > this_ptr : NULL ;
* n = Z_TYPE ( closure - > this_ptr ) ! = IS_NULL ? 1 : 0 ;
2011-11-02 14:31:33 +08:00
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 ) ) ;
2014-02-10 14:04:30 +08:00
closure_handlers . free_obj = zend_closure_free_storage ;
closure_handlers . clone_obj = NULL ;
2008-07-14 17:49:03 +08:00
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 ) ;
2014-02-10 14:04:30 +08:00
closure = ( zend_closure * ) Z_OBJ_P ( res ) ;
2008-07-14 17:49:03 +08:00
closure - > func = * func ;
2011-04-20 20:59:18 +08:00
closure - > func . common . prototype = NULL ;
2008-07-14 17:49:03 +08:00
2014-02-28 20:16:15 +08:00
if ( ( scope = = NULL ) & & this_ptr & & ( Z_TYPE_P ( this_ptr ) ! = IS_UNDEF ) ) {
2011-09-07 14:46:27 +08:00
/* 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 ) ;
2014-05-25 20:04:35 +08:00
zend_hash_apply_with_arguments ( static_variables TSRMLS_CC , 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 ) ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_WARNING , " Cannot bind function %s::%s to scope class %s " , func - > common . scope - > name - > val , func - > common . function_name - > val , scope - > name - > val ) ;
2010-04-20 03:45:03 +08:00
scope = NULL ;
}
2013-02-19 12:56:02 +08:00
if ( scope & & this_ptr & & ( func - > common . fn_flags & ZEND_ACC_STATIC ) = = 0 & &
2010-04-20 03:45:03 +08:00
! instanceof_function ( Z_OBJCE_P ( this_ptr ) , closure - > func . common . scope TSRMLS_CC ) ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_WARNING , " Cannot bind function %s::%s to object of class %s " , func - > common . scope - > name - > val , func - > common . function_name - > val , Z_OBJCE_P ( this_ptr ) - > name - > val ) ;
2010-04-20 03:45:03 +08:00
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
}
2014-06-12 09:07:33 +08:00
ZVAL_UNDEF ( & closure - > this_ptr ) ;
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 ;
2014-02-28 20:06:38 +08:00
if ( this_ptr & & Z_TYPE_P ( this_ptr ) = = IS_OBJECT & & ( closure - > func . common . fn_flags & ZEND_ACC_STATIC ) = = 0 ) {
2014-02-10 14:04:30 +08:00
ZVAL_COPY ( & closure - > this_ptr , this_ptr ) ;
2010-04-20 03:45:03 +08:00
} else {
closure - > func . common . fn_flags | = ZEND_ACC_STATIC ;
}
}
2008-07-14 17:49:03 +08:00
}
/* }}} */
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* indent - tabs - mode : t
* End :
*/