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-10-03 23:32:46 +08:00
zend_function * func = EX ( 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-12-14 06:06:14 +08:00
} else if ( call_user_function_ex ( CG ( function_table ) , NULL , getThis ( ) , return_value , ZEND_NUM_ARGS ( ) , arguments , 1 , NULL ) = = 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-08-26 01:24:55 +08:00
zend_string_release ( func - > internal_function . function_name ) ;
2008-07-26 21:14:04 +08:00
efree ( func ) ;
}
2008-07-14 20:18:23 +08:00
/* }}} */
2014-07-30 08:26:53 +08:00
/* {{{ proto mixed Closure::call(object $to [, mixed $parameter] [, mixed $...] )
2014-08-18 07:03:56 +08:00
Call closure , binding to a given object with its class as the scope */
2014-08-27 12:13:17 +08:00
ZEND_METHOD ( Closure , call )
2014-07-29 09:36:17 +08:00
{
2014-08-18 00:20:02 +08:00
zval * zclosure , * newthis , closure_result ;
2014-07-29 09:36:17 +08:00
zend_closure * closure ;
zend_fcall_info fci ;
zend_fcall_info_cache fci_cache ;
2014-08-18 03:20:23 +08:00
zval * my_params ;
2014-08-27 12:14:17 +08:00
int my_param_count = 0 ;
2014-08-18 06:47:47 +08:00
zend_function my_function ;
2014-07-29 09:36:17 +08:00
2014-12-14 06:06:14 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) , " o* " , & newthis , & my_params , & my_param_count ) = = FAILURE ) {
2014-08-20 07:11:11 +08:00
return ;
2014-07-29 09:36:17 +08:00
}
2014-08-18 03:20:23 +08:00
zclosure = getThis ( ) ;
2014-08-18 00:20:02 +08:00
closure = ( zend_closure * ) Z_OBJ_P ( zclosure ) ;
2014-07-29 09:36:17 +08:00
if ( closure - > func . common . fn_flags & ZEND_ACC_STATIC ) {
zend_error ( E_WARNING , " Cannot bind an instance to a static closure " ) ;
2014-08-20 07:11:11 +08:00
return ;
2014-07-29 09:36:17 +08:00
}
if ( closure - > func . type = = ZEND_INTERNAL_FUNCTION ) {
/* verify that we aren't binding internal function to a wrong object */
2014-08-18 21:47:57 +08:00
if ( ( closure - > func . common . fn_flags & ZEND_ACC_STATIC ) = = 0 & &
2014-12-14 06:06:14 +08:00
! instanceof_function ( Z_OBJCE_P ( newthis ) , closure - > func . common . scope ) ) {
2014-08-18 03:20:23 +08:00
zend_error ( E_WARNING , " Cannot bind function %s::%s to object of class %s " , closure - > func . common . scope - > name - > val , closure - > func . common . function_name - > val , Z_OBJCE_P ( newthis ) - > name - > val ) ;
2014-08-20 07:11:11 +08:00
return ;
2014-07-29 09:36:17 +08:00
}
}
2014-08-18 21:50:05 +08:00
/* This should never happen as closures will always be callable */
2014-12-14 06:06:14 +08:00
if ( zend_fcall_info_init ( zclosure , 0 , & fci , & fci_cache , NULL , NULL ) ! = SUCCESS ) {
2014-08-18 21:47:57 +08:00
ZEND_ASSERT ( 0 ) ;
2014-08-18 03:20:23 +08:00
}
2014-08-18 00:20:02 +08:00
fci . retval = & closure_result ;
2014-08-18 03:20:23 +08:00
fci . params = my_params ;
fci . param_count = my_param_count ;
fci . object = fci_cache . object = Z_OBJ_P ( newthis ) ;
2014-07-29 09:36:17 +08:00
fci_cache . initialized = 1 ;
2014-08-18 06:47:47 +08:00
my_function = * fci_cache . function_handler ;
/* use scope of passed object */
my_function . common . scope = Z_OBJCE_P ( newthis ) ;
fci_cache . function_handler = & my_function ;
2014-07-29 09:36:17 +08:00
2014-12-14 06:06:14 +08:00
if ( zend_call_function ( & fci , & fci_cache ) = = SUCCESS & & Z_TYPE ( closure_result ) ! = IS_UNDEF ) {
2014-08-18 03:20:23 +08:00
ZVAL_COPY_VALUE ( return_value , & closure_result ) ;
2014-07-29 09:36:17 +08:00
}
}
/* }}} */
2014-08-18 06:47:47 +08:00
/* {{{ proto Closure Closure::bind(Closure $old, object $to [, mixed $scope = "static" ] )
2011-09-07 14:46:27 +08:00
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
2014-12-14 06:06:14 +08:00
if ( zend_parse_method_parameters ( ZEND_NUM_ARGS ( ) , 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 */
2014-10-09 19:58:14 +08:00
if ( Z_TYPE_P ( scope_arg ) = = IS_OBJECT ) {
2011-09-07 14:46:27 +08:00
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-08-26 04:40:58 +08:00
if ( zend_string_equals_literal ( class_name , " static " ) ) {
2011-09-07 14:46:27 +08:00
ce = closure - > func . common . scope ;
2014-12-14 06:06:14 +08:00
} else if ( ( ce = zend_lookup_class_ex ( class_name , NULL , 1 ) ) = = NULL ) {
2014-02-10 14:04:30 +08:00
zend_error ( E_WARNING , " Class '%s' not found " , class_name - > val ) ;
2014-08-26 01:24:55 +08:00
zend_string_release ( class_name ) ;
2011-09-07 14:46:27 +08:00
RETURN_NULL ( ) ;
}
2014-08-26 01:24:55 +08:00
zend_string_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
2014-12-14 06:06:14 +08:00
zend_create_closure ( return_value , & closure - > func , ce , newthis ) ;
2010-04-20 03:45:03 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zend_function * zend_closure_get_constructor ( zend_object * object ) /* { { { */
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 ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
static int zend_closure_compare_objects ( zval * o1 , zval * o2 ) /* { { { */
2008-07-14 17:49:03 +08:00
{
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-12-14 06:06:14 +08:00
ZEND_API zend_function * zend_get_closure_invoke_method ( zend_object * object ) /* { { { */
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 ;
2014-12-03 21:56:09 +08:00
/* TODO: return ZEND_INTERNAL_FUNCTION, but arg_info representation is suitable for ZEND_USER_FUNCTION ??? */
2008-08-11 16:49:00 +08:00
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-08-26 01:24:55 +08:00
invoke - > internal_function . function_name = zend_string_init ( ZEND_INVOKE_FUNC_NAME , sizeof ( ZEND_INVOKE_FUNC_NAME ) - 1 , 0 ) ;
2008-08-11 16:49:00 +08:00
return invoke ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API const zend_function * zend_get_closure_method_def ( zval * obj ) /* { { { */
2009-01-03 20:25:59 +08:00
{
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 ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API zval * zend_get_closure_this_ptr ( zval * obj ) /* { { { */
2010-04-20 03:45:03 +08:00
{
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-12-14 06:06:14 +08:00
static zend_function * zend_closure_get_method ( zend_object * * object , zend_string * method , const zval * key ) /* { { { */
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-12-24 20:04:51 +08:00
lc_name = zend_string_tolower ( method ) ;
2014-08-26 04:40:58 +08:00
if ( zend_string_equals_literal ( method , ZEND_INVOKE_FUNC_NAME ) ) {
2014-12-24 20:04:51 +08:00
zend_string_release ( lc_name ) ;
2014-12-14 06:06:14 +08:00
return zend_get_closure_invoke_method ( * object ) ;
2008-07-14 17:49:03 +08:00
}
2014-12-24 20:04:51 +08:00
zend_string_release ( lc_name ) ;
2014-12-14 06:06:14 +08:00
return std_object_handlers . get_method ( object , method , key ) ;
2008-07-14 17:49:03 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zval * zend_closure_read_property ( zval * object , zval * member , int type , void * * cache_slot , zval * rv ) /* { { { */
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-12-14 06:06:14 +08:00
static void zend_closure_write_property ( zval * object , zval * member , zval * value , void * * cache_slot ) /* { { { */
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-12-14 06:06:14 +08:00
static zval * zend_closure_get_property_ptr_ptr ( zval * object , zval * member , int type , void * * cache_slot ) /* { { { */
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-12-14 06:06:14 +08:00
static int zend_closure_has_property ( zval * object , zval * member , int has_set_exists , void * * cache_slot ) /* { { { */
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-12-14 06:06:14 +08:00
static void zend_closure_unset_property ( zval * object , zval * member , void * * cache_slot ) /* { { { */
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-12-14 06:06:14 +08:00
static void zend_closure_free_storage ( zend_object * object ) /* { { { */
2008-07-14 17:49:03 +08:00
{
zend_closure * closure = ( zend_closure * ) object ;
2014-12-14 06:06:14 +08:00
zend_object_std_dtor ( & closure - > std ) ;
2008-07-14 17:49:03 +08:00
if ( closure - > func . type = = ZEND_USER_FUNCTION ) {
zend_execute_data * ex = EG ( current_execute_data ) ;
while ( ex ) {
2014-06-27 03:51:14 +08:00
if ( ex - > func = = & closure - > func ) {
2008-07-14 17:49:03 +08:00
zend_error ( E_ERROR , " Cannot destroy active lambda function " ) ;
}
ex = ex - > prev_execute_data ;
}
2014-12-14 06:06:14 +08:00
destroy_op_array ( & closure - > func . op_array ) ;
2008-07-14 17:49:03 +08:00
}
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-12-14 06:06:14 +08:00
static zend_object * zend_closure_new ( zend_class_entry * class_type ) /* { { { */
2008-07-14 17:49:03 +08:00
{
zend_closure * closure ;
closure = emalloc ( sizeof ( zend_closure ) ) ;
memset ( closure , 0 , sizeof ( zend_closure ) ) ;
2014-12-14 06:06:14 +08:00
zend_object_std_init ( & closure - > std , class_type ) ;
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-12-14 06:06:14 +08:00
static zend_object * zend_closure_clone ( zval * zobject ) /* { { { */
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-12-14 06:06:14 +08:00
zend_create_closure ( & result , & closure - > func , closure - > func . common . scope , & closure - > this_ptr ) ;
2014-02-10 14:04:30 +08:00
return Z_OBJ ( result ) ;
2010-04-20 03:45:03 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
int zend_closure_get_closure ( zval * obj , zend_class_entry * * ce_ptr , zend_function * * fptr_ptr , zend_object * * obj_ptr ) /* { { { */
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 ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
static HashTable * zend_closure_get_debug_info ( zval * object , int * is_temp ) /* { { { */
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 ) {
2014-12-22 21:44:39 +08:00
uint32_t i , num_args , required = closure - > func . common . required_num_args ;
2009-08-10 23:18:13 +08:00
2014-02-10 14:04:30 +08:00
array_init ( & val ) ;
2009-08-10 23:18:13 +08:00
2014-12-22 21:44:39 +08:00
num_args = closure - > func . common . num_args ;
if ( closure - > func . common . fn_flags & ZEND_ACC_VARIADIC ) {
num_args + + ;
}
for ( i = 0 ; i < 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 ? " & " : " " ,
2014-12-03 21:56:09 +08:00
arg_info - > name - > val ) ;
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-09-19 19:41:01 +08:00
ZVAL_NEW_STR ( & info , zend_strpprintf ( 0 , " %s " , i > = required ? " <optional> " : " <required> " ) ) ;
2014-05-10 00:21:49 +08:00
zend_hash_update ( Z_ARRVAL ( val ) , name , & info ) ;
2014-08-26 01:24:55 +08:00
zend_string_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-12-14 06:06:14 +08:00
static HashTable * zend_closure_get_gc ( zval * obj , zval * * table , int * n ) /* { { { */
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 ;
}
2011-11-02 14:31:33 +08:00
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 ( )
2014-07-30 08:26:53 +08:00
ZEND_BEGIN_ARG_INFO_EX ( arginfo_closure_call , 0 , 0 , 1 )
2014-07-29 09:36:17 +08:00
ZEND_ARG_INFO ( 0 , newthis )
ZEND_ARG_VARIADIC_INFO ( 0 , parameters )
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 )
2014-07-30 08:26:53 +08:00
ZEND_ME ( Closure , call , arginfo_closure_call , ZEND_ACC_PUBLIC )
2014-12-13 02:57:34 +08:00
ZEND_FE_END
2009-01-04 03:29:55 +08:00
} ;
2014-12-14 06:06:14 +08:00
void zend_register_closure_ce ( void ) /* { { { */
2008-07-14 17:49:03 +08:00
{
zend_class_entry ce ;
2009-01-04 03:29:55 +08:00
INIT_CLASS_ENTRY ( ce , " Closure " , closure_functions ) ;
2014-12-14 06:06:14 +08:00
zend_ce_closure = zend_register_internal_class ( & ce ) ;
2014-11-22 12:57:55 +08:00
zend_ce_closure - > ce_flags | = ZEND_ACC_FINAL ;
2008-07-14 17:49:03 +08:00
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
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API void zend_create_closure ( zval * res , zend_function * func , zend_class_entry * scope , zval * this_ptr ) /* { { { */
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-12-14 06:06:14 +08:00
zend_hash_apply_with_arguments ( static_variables , 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 ) {
2014-12-14 06:06:14 +08:00
if ( scope & & ! instanceof_function ( scope , func - > common . scope ) ) {
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 & &
2014-12-14 06:06:14 +08:00
! instanceof_function ( Z_OBJCE_P ( this_ptr ) , closure - > func . common . scope ) ) {
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:
2014-08-18 06:54:23 +08:00
* 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 ) ;
2014-08-18 06:54:23 +08:00
} else {
2010-04-20 03:45:03 +08:00
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 :
*/