dmitry Tue Jul 8 07:05:04 2008 UTC Added files: /ZendEngine2 zend_closures.c zend_closures.h /ZendEngine2/tests closure_001.phpt closure_002.phpt closure_003.phpt closure_004.phpt closure_005.phpt closure_006.phpt closure_007.phpt closure_008.phpt closure_009.phpt closure_010.phpt closure_011.phpt closure_012.phpt
Modified files: /php-src NEWS configure.in /ZendEngine2 Makefile.am Zend.dsp ZendTS.dsp zend.h zend_API.c zend_compile.c zend_compile.h zend_default_classes.c zend_execute.c zend_execute_API.c zend_language_parser.y zend_vm_def.h zend_vm_execute.h zend_vm_opcodes.h /php-src/ext/pcre php_pcre.c /php-src/ext/reflection php_reflection.c Log: Added closures support
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2162&r2=1.2163&diff_format=u Index: php-src/NEWS diff -u php-src/NEWS:1.2162 php-src/NEWS:1.2163 --- php-src/NEWS:1.2162 Wed May 7 15:51:34 2008 +++ php-src/NEWS Tue Jul 8 07:05:03 2008 @@ -2,6 +2,7 @@ ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 20??, PHP 6.0 - Unicode support. (Andrei, Dmitry, et al) +- Closures (Christian Seiler, Dmitry) - Changed dl() to be disabled by default. Enabled only when explicitly registered by the SAPI layer. Enabled only with CLI, CGI and EMBED. (Dmitry) http://cvs.php.net/viewvc.cgi/php-src/configure.in?r1=1.657&r2=1.658&diff_format=u Index: php-src/configure.in diff -u php-src/configure.in:1.657 php-src/configure.in:1.658 --- php-src/configure.in:1.657 Mon Jun 2 16:29:25 2008 +++ php-src/configure.in Tue Jul 8 07:05:03 2008 @@ -1,4 +1,4 @@ -## $Id: configure.in,v 1.657 2008/06/02 16:29:25 helly Exp $ -*- autoconf -*- +## $Id: configure.in,v 1.658 2008/07/08 07:05:03 dmitry Exp $ -*- autoconf -*- dnl ## Process this file with autoconf to produce a configure script. divert(1) @@ -1334,7 +1334,7 @@ zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ zend_ini.c zend_qsort.c zend_ts_hash.c zend_stream.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c \ - zend_strtol.c zend_gc.c) + zend_strtol.c zend_gc.c zend_closures.c) if test -r "$abs_srcdir/Zend/zend_objects.c"; then PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c \ http://cvs.php.net/viewvc.cgi/ZendEngine2/Makefile.am?r1=1.62&r2=1.63&diff_format=u Index: ZendEngine2/Makefile.am diff -u ZendEngine2/Makefile.am:1.62 ZendEngine2/Makefile.am:1.63 --- ZendEngine2/Makefile.am:1.62 Wed Mar 26 14:23:01 2008 +++ ZendEngine2/Makefile.am Tue Jul 8 07:05:03 2008 @@ -17,7 +17,7 @@ zend_objects_API.c zend_ts_hash.c zend_stream.c \ zend_default_classes.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c \ - zend_strtod.c zend_strtod.c zend_strtol.c + zend_strtod.c zend_strtod.c zend_strtol.c zend_closures.c libZend_la_LDFLAGS = libZend_la_LIBADD = @ZEND_EXTRA_LIBS@ http://cvs.php.net/viewvc.cgi/ZendEngine2/Zend.dsp?r1=1.26&r2=1.27&diff_format=u Index: ZendEngine2/Zend.dsp diff -u ZendEngine2/Zend.dsp:1.26 ZendEngine2/Zend.dsp:1.27 --- ZendEngine2/Zend.dsp:1.26 Tue Dec 5 08:08:33 2006 +++ ZendEngine2/Zend.dsp Tue Jul 8 07:05:03 2008 @@ -123,6 +123,10 @@ # End Source File # Begin Source File +SOURCE=.\zend_closures.c +# End Source File +# Begin Source File + SOURCE=.\zend_compile.c # End Source File # Begin Source File http://cvs.php.net/viewvc.cgi/ZendEngine2/ZendTS.dsp?r1=1.48&r2=1.49&diff_format=u Index: ZendEngine2/ZendTS.dsp diff -u ZendEngine2/ZendTS.dsp:1.48 ZendEngine2/ZendTS.dsp:1.49 --- ZendEngine2/ZendTS.dsp:1.48 Tue Dec 5 08:08:33 2006 +++ ZendEngine2/ZendTS.dsp Tue Jul 8 07:05:03 2008 @@ -148,6 +148,10 @@ # End Source File # Begin Source File +SOURCE=.\zend_closures.c +# End Source File +# Begin Source File + SOURCE=.\zend_compile.c # End Source File # Begin Source File http://cvs.php.net/viewvc.cgi/ZendEngine2/zend.h?r1=1.355&r2=1.356&diff_format=u Index: ZendEngine2/zend.h diff -u ZendEngine2/zend.h:1.355 ZendEngine2/zend.h:1.356 --- ZendEngine2/zend.h:1.355 Fri Jun 27 18:45:15 2008 +++ ZendEngine2/zend.h Tue Jul 8 07:05:03 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend.h,v 1.355 2008/06/27 18:45:15 stas Exp $ */ +/* $Id: zend.h,v 1.356 2008/07/08 07:05:03 dmitry Exp $ */ #ifndef ZEND_H #define ZEND_H @@ -561,6 +561,8 @@ #define IS_CONSTANT_TYPE_MASK 0x0f #define IS_CONSTANT_RT_NS_CHECK 0x10 #define IS_CONSTANT_INDEX 0x80 +#define IS_LEXICAL_VAR 0x20 +#define IS_LEXICAL_REF 0x40 /* overloaded elements data types */ #define OE_IS_ARRAY (1<<0) http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_API.c?r1=1.473&r2=1.474&diff_format=u Index: ZendEngine2/zend_API.c diff -u ZendEngine2/zend_API.c:1.473 ZendEngine2/zend_API.c:1.474 --- ZendEngine2/zend_API.c:1.473 Thu Jun 5 19:16:17 2008 +++ ZendEngine2/zend_API.c Tue Jul 8 07:05:03 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_API.c,v 1.473 2008/06/05 19:16:17 felipe Exp $ */ +/* $Id: zend_API.c,v 1.474 2008/07/08 07:05:03 dmitry Exp $ */ #include "zend.h" #include "zend_execute.h" @@ -26,6 +26,7 @@ #include "zend_modules.h" #include "zend_constants.h" #include "zend_exceptions.h" +#include "zend_closures.h" #ifdef HAVE_STDARG_H #include <stdarg.h> @@ -3093,6 +3094,15 @@ } return 0; + case IS_OBJECT: + if (zend_get_closure(callable, ce_ptr, fptr_ptr, NULL, zobj_ptr_ptr TSRMLS_CC) == SUCCESS) { + if (callable_name) { + ZVAL_ZSTR(callable_name, UG(unicode) ? IS_UNICODE : IS_STRING, (*fptr_ptr)->common.function_name, 1); + } + return 1; + } + /* break missing intentionally */ + default: if (callable_name) { *callable_name = *callable; http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_compile.c?r1=1.827&r2=1.828&diff_format=u Index: ZendEngine2/zend_compile.c diff -u ZendEngine2/zend_compile.c:1.827 ZendEngine2/zend_compile.c:1.828 --- ZendEngine2/zend_compile.c:1.827 Fri Jun 20 17:17:18 2008 +++ ZendEngine2/zend_compile.c Tue Jul 8 07:05:03 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_compile.c,v 1.827 2008/06/20 17:17:18 dmitry Exp $ */ +/* $Id: zend_compile.c,v 1.828 2008/07/08 07:05:03 dmitry Exp $ */ #include <zend_language_parser.h> #include "zend.h" @@ -1474,6 +1474,33 @@ } /* }}} */ +void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference, int is_static TSRMLS_DC) /* {{{ */ +{ + znode function_name; + zend_op_array *current_op_array = CG(active_op_array); + int current_op_number = get_next_op_number(CG(active_op_array)); + zend_op *current_op; + + function_name.op_type = IS_CONST; + ZVAL_ASCII_STRING(&function_name.u.constant, "lambda", ZSTR_DUPLICATE); + + zend_do_begin_function_declaration(function_token, &function_name, 0, return_reference, NULL TSRMLS_CC); + + result->op_type = IS_TMP_VAR; + result->u.var = get_temporary_variable(current_op_array);; + + current_op = ¤t_op_array->opcodes[current_op_number]; + current_op->opcode = ZEND_DECLARE_LAMBDA_FUNCTION; + zval_dtor(¤t_op->op2.u.constant); + ZVAL_LONG(¤t_op->op2.u.constant, zend_u_hash_func(Z_TYPE(current_op->op1.u.constant), Z_UNIVAL(current_op->op1.u.constant), Z_UNILEN(current_op->op1.u.constant))); + current_op->result = *result; + if (is_static) { + CG(active_op_array)->fn_flags |= ZEND_ACC_STATIC; + } + CG(active_op_array)->fn_flags |= ZEND_ACC_CLOSURE; +} +/* }}} */ + void zend_do_handle_exception(TSRMLS_D) /* {{{ */ { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -4374,13 +4401,13 @@ } opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_FETCH_W; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */ + opline->opcode = (fetch_type == ZEND_FETCH_LEXICAL) ? ZEND_FETCH_R : ZEND_FETCH_W; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */ opline->result.op_type = IS_VAR; opline->result.u.EA.type = 0; opline->result.u.var = get_temporary_variable(CG(active_op_array)); opline->op1 = *varname; SET_UNUSED(opline->op2); - opline->op2.u.EA.type = fetch_type; + opline->op2.u.EA.type = ZEND_FETCH_STATIC; result = opline->result; if (varname->op_type == IS_CONST) { @@ -4388,13 +4415,40 @@ } fetch_simple_variable(&lval, varname, 0 TSRMLS_CC); /* Relies on the fact that the default fetch is BP_VAR_W */ - zend_do_assign_ref(NULL, &lval, &result TSRMLS_CC); - CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED; + if (fetch_type == ZEND_FETCH_LEXICAL) { + znode dummy; + + zend_do_begin_variable_parse(TSRMLS_C); + zend_do_assign(&dummy, &lval, &result TSRMLS_CC); + zend_do_free(&dummy TSRMLS_CC); + } else { + zend_do_assign_ref(NULL, &lval, &result TSRMLS_CC); + } CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED; /* zval_dtor(&varname->u.constant); */ } /* }}} */ +void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC) /* {{{ */ +{ + znode value; + + if (Z_UNILEN(varname->u.constant) == sizeof("this") - 1 && + ZEND_U_EQUAL(UG(unicode)?IS_UNICODE:IS_STRING, Z_UNIVAL(varname->u.constant), Z_UNILEN(varname->u.constant), "this", sizeof("this")-1)) { + zend_error(E_COMPILE_ERROR, "Cannot use $this as lexical variable"); + return; + } + + value.op_type = IS_CONST; + ZVAL_NULL(&value.u.constant); + Z_TYPE(value.u.constant) |= is_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR; + Z_SET_REFCOUNT_P(&value.u.constant, 1); + Z_UNSET_ISREF_P(&value.u.constant); + + zend_do_fetch_static_variable(varname, &value, is_ref ? ZEND_FETCH_STATIC : ZEND_FETCH_LEXICAL TSRMLS_CC); +} +/* }}} */ + void zend_do_fetch_global_variable(znode *varname, znode *static_assignment, int fetch_type TSRMLS_DC) /* {{{ */ { zend_op *opline; http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_compile.h?r1=1.382&r2=1.383&diff_format=u Index: ZendEngine2/zend_compile.h diff -u ZendEngine2/zend_compile.h:1.382 ZendEngine2/zend_compile.h:1.383 --- ZendEngine2/zend_compile.h:1.382 Wed Jun 11 13:19:14 2008 +++ ZendEngine2/zend_compile.h Tue Jul 8 07:05:03 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_compile.h,v 1.382 2008/06/11 13:19:14 dmitry Exp $ */ +/* $Id: zend_compile.h,v 1.383 2008/07/08 07:05:03 dmitry Exp $ */ #ifndef ZEND_COMPILE_H #define ZEND_COMPILE_H @@ -151,6 +151,7 @@ /* class implement interface(s) flag */ #define ZEND_ACC_IMPLEMENT_INTERFACES 0x80000 +#define ZEND_ACC_CLOSURE 0x100000 char *zend_visibility_string(zend_uint fn_flags); @@ -438,6 +439,9 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC); void zend_do_handle_exception(TSRMLS_D); +void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference, int is_static TSRMLS_DC); +void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC); + void zend_do_try(znode *try_token TSRMLS_DC); void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, znode *first_catch TSRMLS_DC); void zend_do_end_catch(znode *try_token TSRMLS_DC); @@ -640,7 +644,7 @@ #define ZEND_FETCH_STATIC_MEMBER 3 #define ZEND_FETCH_GLOBAL_LOCK 4 #define ZEND_FETCH_AUTO_GLOBAL 5 - +#define ZEND_FETCH_LEXICAL 6 /* class fetches */ #define ZEND_FETCH_CLASS_DEFAULT 0 http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_default_classes.c?r1=1.65&r2=1.66&diff_format=u Index: ZendEngine2/zend_default_classes.c diff -u ZendEngine2/zend_default_classes.c:1.65 ZendEngine2/zend_default_classes.c:1.66 --- ZendEngine2/zend_default_classes.c:1.65 Mon Dec 31 07:12:06 2007 +++ ZendEngine2/zend_default_classes.c Tue Jul 8 07:05:03 2008 @@ -17,13 +17,14 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_default_classes.c,v 1.65 2007/12/31 07:12:06 sebastian Exp $ */ +/* $Id: zend_default_classes.c,v 1.66 2008/07/08 07:05:03 dmitry Exp $ */ #include "zend.h" #include "zend_API.h" #include "zend_builtin_functions.h" #include "zend_interfaces.h" #include "zend_exceptions.h" +#include "zend_closures.h" ZEND_API void zend_register_default_classes(TSRMLS_D) /* {{{ */ { @@ -31,6 +32,7 @@ zend_register_default_exception(TSRMLS_C); zend_register_unicode_exceptions(TSRMLS_C); zend_register_iterator_wrapper(TSRMLS_C); + zend_register_closure_ce(TSRMLS_C); } /* }}} */ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_execute.c?r1=1.799&r2=1.800&diff_format=u Index: ZendEngine2/zend_execute.c diff -u ZendEngine2/zend_execute.c:1.799 ZendEngine2/zend_execute.c:1.800 --- ZendEngine2/zend_execute.c:1.799 Tue Jul 1 13:21:12 2008 +++ ZendEngine2/zend_execute.c Tue Jul 8 07:05:03 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_execute.c,v 1.799 2008/07/01 13:21:12 dmitry Exp $ */ +/* $Id: zend_execute.c,v 1.800 2008/07/08 07:05:03 dmitry Exp $ */ #define ZEND_INTENSIVE_DEBUGGING 0 @@ -34,6 +34,7 @@ #include "zend_ini.h" #include "zend_exceptions.h" #include "zend_interfaces.h" +#include "zend_closures.h" #include "zend_vm.h" #include "zend_unicode.h" http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_execute_API.c?r1=1.450&r2=1.451&diff_format=u Index: ZendEngine2/zend_execute_API.c diff -u ZendEngine2/zend_execute_API.c:1.450 ZendEngine2/zend_execute_API.c:1.451 --- ZendEngine2/zend_execute_API.c:1.450 Thu Jun 5 19:14:25 2008 +++ ZendEngine2/zend_execute_API.c Tue Jul 8 07:05:03 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_execute_API.c,v 1.450 2008/06/05 19:14:25 felipe Exp $ */ +/* $Id: zend_execute_API.c,v 1.451 2008/07/08 07:05:03 dmitry Exp $ */ #include <stdio.h> #include <signal.h> @@ -29,6 +29,7 @@ #include "zend_ptr_stack.h" #include "zend_constants.h" #include "zend_extensions.h" +#include "zend_closures.h" #include "zend_exceptions.h" #include "zend_vm.h" #ifdef HAVE_SYS_TIME_H @@ -889,7 +890,11 @@ } } - if (Z_TYPE_P(fci->function_name) != IS_STRING && + if (Z_TYPE_P(fci->function_name) == IS_OBJECT) { + if (zend_get_closure(fci->function_name, &calling_scope, &EX(function_state).function, NULL, &fci->object_pp TSRMLS_CC) == SUCCESS) { + goto init_fci_cache; + } + } else if (Z_TYPE_P(fci->function_name) != IS_STRING && Z_TYPE_P(fci->function_name) != IS_UNICODE ) { return FAILURE; @@ -1035,6 +1040,8 @@ return FAILURE; } } + +init_fci_cache: if (fci_cache && (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION || ((zend_internal_function*)EX(function_state).function)->handler != zend_std_call_user_call) http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_language_parser.y?r1=1.206&r2=1.207&diff_format=u Index: ZendEngine2/zend_language_parser.y diff -u ZendEngine2/zend_language_parser.y:1.206 ZendEngine2/zend_language_parser.y:1.207 --- ZendEngine2/zend_language_parser.y:1.206 Sun Jun 8 09:51:42 2008 +++ ZendEngine2/zend_language_parser.y Tue Jul 8 07:05:03 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_language_parser.y,v 1.206 2008/06/08 09:51:42 stas Exp $ */ +/* $Id: zend_language_parser.y,v 1.207 2008/07/08 07:05:03 dmitry Exp $ */ /* * LALR shift/reduce conflicts and how they are resolved: @@ -304,7 +304,7 @@ unticked_function_declaration_statement: - T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type, NULL TSRMLS_CC); } + function is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$3, 0, $2.op_type, NULL TSRMLS_CC); } '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); } ; @@ -512,8 +512,8 @@ class_statement: variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration ';' | class_constant_declaration ';' - | method_modifiers T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, &$1 TSRMLS_CC); } '(' - parameter_list ')' method_body { zend_do_abstract_method(&$5, &$1, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); } + | method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); } '(' + parameter_list ')' method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); } ; @@ -647,10 +647,30 @@ | T_ARRAY '(' array_pair_list ')' { $$ = $3; } | '`' { CG(literal_type) = UG(unicode)?IS_UNICODE:IS_STRING; } encaps_list '`' { zend_do_shell_exec(&$$, &$3 TSRMLS_CC); } | T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); } + | function is_reference '(' { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); } + parameter_list ')' lexical_vars '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $4; } + | T_STATIC function is_reference '(' { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); } + parameter_list ')' lexical_vars '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $5; } +; + +function: + T_FUNCTION { $$.u.opline_num = CG(zend_lineno); } +; + +lexical_vars: + /* emptry */ + | T_USE '(' lexical_var_list ')' +; + +lexical_var_list: + lexical_var_list ',' T_VARIABLE { zend_do_fetch_lexical_variable(&$3, 0 TSRMLS_CC); } + | lexical_var_list ',' '&' T_VARIABLE { zend_do_fetch_lexical_variable(&$4, 1 TSRMLS_CC); } + | T_VARIABLE { zend_do_fetch_lexical_variable(&$1, 0 TSRMLS_CC); } + | '&' T_VARIABLE { zend_do_fetch_lexical_variable(&$2, 1 TSRMLS_CC); } ; function_call: - T_STRING '(' { $2.u.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); } + T_STRING '(' { $2.u.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, $2.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } | T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { $3.u.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_vm_def.h?r1=1.233&r2=1.234&diff_format=u Index: ZendEngine2/zend_vm_def.h diff -u ZendEngine2/zend_vm_def.h:1.233 ZendEngine2/zend_vm_def.h:1.234 --- ZendEngine2/zend_vm_def.h:1.233 Wed Jun 11 13:19:14 2008 +++ ZendEngine2/zend_vm_def.h Tue Jul 8 07:05:03 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_vm_def.h,v 1.233 2008/06/11 13:19:14 dmitry Exp $ */ +/* $Id: zend_vm_def.h,v 1.234 2008/07/08 07:05:03 dmitry Exp $ */ /* If you change this file, please regenerate the zend_vm_execute.h and * zend_vm_opcodes.h files by running: @@ -2086,6 +2086,15 @@ } else { function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); + if (Z_TYPE_P(function_name) == IS_OBJECT && + zend_get_closure(function_name, &EX(called_scope), &EX(fbc), &EX(object), NULL TSRMLS_CC) == SUCCESS) { + if (EX(object)) { + Z_ADDREF_P(EX(object)); + } + FREE_OP2(); + ZEND_VM_NEXT_OPCODE(); + } + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } @@ -4533,4 +4542,19 @@ ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, CONST) +{ + zend_op *opline = EX(opline); + zend_op_array *op_array; + + if (zend_u_hash_quick_find(EG(function_table), UG(unicode)?IS_UNICODE:IS_STRING, Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), Z_LVAL(opline->op2.u.constant), (void *) &op_array) == FAILURE || + op_array->type != ZEND_USER_FUNCTION) { + zend_error_noreturn(E_ERROR, "Base lambda function for closure not found"); + } + + zend_create_closure(&EX_T(opline->result.u.var).tmp_var, op_array, EG(scope), EG(This) TSRMLS_CC); + + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper) http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_vm_execute.h?r1=1.237&r2=1.238&diff_format=u Index: ZendEngine2/zend_vm_execute.h diff -u ZendEngine2/zend_vm_execute.h:1.237 ZendEngine2/zend_vm_execute.h:1.238 --- ZendEngine2/zend_vm_execute.h:1.237 Wed Jun 11 13:19:14 2008 +++ ZendEngine2/zend_vm_execute.h Tue Jul 8 07:05:03 2008 @@ -756,6 +756,15 @@ } else { function_name = &opline->op2.u.constant; + if (Z_TYPE_P(function_name) == IS_OBJECT && + zend_get_closure(function_name, &EX(called_scope), &EX(fbc), &EX(object), NULL TSRMLS_CC) == SUCCESS) { + if (EX(object)) { + Z_ADDREF_P(EX(object)); + } + + ZEND_VM_NEXT_OPCODE(); + } + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } @@ -946,6 +955,15 @@ } else { function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + if (Z_TYPE_P(function_name) == IS_OBJECT && + zend_get_closure(function_name, &EX(called_scope), &EX(fbc), &EX(object), NULL TSRMLS_CC) == SUCCESS) { + if (EX(object)) { + Z_ADDREF_P(EX(object)); + } + zval_dtor(free_op2.var); + ZEND_VM_NEXT_OPCODE(); + } + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } @@ -1024,6 +1042,15 @@ } else { function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + if (Z_TYPE_P(function_name) == IS_OBJECT && + zend_get_closure(function_name, &EX(called_scope), &EX(fbc), &EX(object), NULL TSRMLS_CC) == SUCCESS) { + if (EX(object)) { + Z_ADDREF_P(EX(object)); + } + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + ZEND_VM_NEXT_OPCODE(); + } + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } @@ -1131,6 +1158,15 @@ } else { function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); + if (Z_TYPE_P(function_name) == IS_OBJECT && + zend_get_closure(function_name, &EX(called_scope), &EX(fbc), &EX(object), NULL TSRMLS_CC) == SUCCESS) { + if (EX(object)) { + Z_ADDREF_P(EX(object)); + } + + ZEND_VM_NEXT_OPCODE(); + } + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } @@ -2960,6 +2996,21 @@ ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zend_op_array *op_array; + + if (zend_u_hash_quick_find(EG(function_table), UG(unicode)?IS_UNICODE:IS_STRING, Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), Z_LVAL(opline->op2.u.constant), (void *) &op_array) == FAILURE || + op_array->type != ZEND_USER_FUNCTION) { + zend_error_noreturn(E_ERROR, "Base lambda function for closure not found"); + } + + zend_create_closure(&EX_T(opline->result.u.var).tmp_var, op_array, EG(scope), EG(This) TSRMLS_CC); + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_ADD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -34712,6 +34763,31 @@ ZEND_JMP_SET_SPEC_CV_HANDLER, ZEND_JMP_SET_SPEC_CV_HANDLER, ZEND_JMP_SET_SPEC_CV_HANDLER, + ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_CONST_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = (opcode_handler_t*)labels; http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_vm_opcodes.h?r1=1.73&r2=1.74&diff_format=u Index: ZendEngine2/zend_vm_opcodes.h diff -u ZendEngine2/zend_vm_opcodes.h:1.73 ZendEngine2/zend_vm_opcodes.h:1.74 --- ZendEngine2/zend_vm_opcodes.h:1.73 Tue Mar 18 08:36:49 2008 +++ ZendEngine2/zend_vm_opcodes.h Tue Jul 8 07:05:03 2008 @@ -153,3 +153,4 @@ #define ZEND_USER_OPCODE 150 #define ZEND_U_NORMALIZE 151 #define ZEND_JMP_SET 152 +#define ZEND_DECLARE_LAMBDA_FUNCTION 153 http://cvs.php.net/viewvc.cgi/php-src/ext/pcre/php_pcre.c?r1=1.235&r2=1.236&diff_format=u Index: php-src/ext/pcre/php_pcre.c diff -u php-src/ext/pcre/php_pcre.c:1.235 php-src/ext/pcre/php_pcre.c:1.236 --- php-src/ext/pcre/php_pcre.c:1.235 Mon Jun 30 13:47:22 2008 +++ php-src/ext/pcre/php_pcre.c Tue Jul 8 07:05:04 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_pcre.c,v 1.235 2008/06/30 13:47:22 felipe Exp $ */ +/* $Id: php_pcre.c,v 1.236 2008/07/08 07:05:04 dmitry Exp $ */ /* TODO * php_pcre_replace_impl(): @@ -1460,7 +1460,7 @@ } if (is_callable_replace) { - if (Z_TYPE_P(replace) != IS_ARRAY) { + if (Z_TYPE_P(replace) != IS_ARRAY && Z_TYPE_P(replace) != IS_OBJECT) { convert_to_text(replace); } if (!zend_is_callable(replace, 0, &callback_name)) { http://cvs.php.net/viewvc.cgi/php-src/ext/reflection/php_reflection.c?r1=1.298&r2=1.299&diff_format=u Index: php-src/ext/reflection/php_reflection.c diff -u php-src/ext/reflection/php_reflection.c:1.298 php-src/ext/reflection/php_reflection.c:1.299 --- php-src/ext/reflection/php_reflection.c:1.298 Fri Jun 27 06:43:38 2008 +++ php-src/ext/reflection/php_reflection.c Tue Jul 8 07:05:04 2008 @@ -20,7 +20,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_reflection.c,v 1.298 2008/06/27 06:43:38 dmitry Exp $ */ +/* $Id: php_reflection.c,v 1.299 2008/07/08 07:05:04 dmitry Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -38,6 +38,7 @@ #include "zend_constants.h" #include "zend_ini.h" #include "zend_interfaces.h" +#include "zend_closures.h" /* Class entry pointers */ PHPAPI zend_class_entry *reflector_ptr; @@ -1586,6 +1587,20 @@ } /* }}} */ +/* {{{ proto public mixed ReflectionFunction::getClosure() + Invokes the function */ +ZEND_METHOD(reflection_function, getClosure) +{ + reflection_object *intern; + zend_function *fptr; + + METHOD_NOTSTATIC_NUMPARAMS(reflection_function_ptr, 0); + GET_REFLECTION_OBJECT_PTR(fptr); + + zend_create_closure(return_value, fptr, NULL, NULL TSRMLS_CC); +} +/* }}} */ + /* {{{ proto public mixed ReflectionFunction::invoke(mixed* args) U Invokes the function */ ZEND_METHOD(reflection_function, invoke) @@ -2333,6 +2348,34 @@ } /* }}} */ +/* {{{ proto public mixed ReflectionMethod::getClosure([mixed object]) + Invokes the function */ +ZEND_METHOD(reflection_method, getClosure) +{ + reflection_object *intern; + zval *obj; + zend_function *mptr; + + METHOD_NOTSTATIC(reflection_method_ptr); + GET_REFLECTION_OBJECT_PTR(mptr); + + if (mptr->common.fn_flags & ZEND_ACC_STATIC) { + zend_create_closure(return_value, mptr, mptr->common.scope, NULL TSRMLS_CC); + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + + if (!instanceof_function(Z_OBJCE_P(obj), mptr->common.scope TSRMLS_CC)) { + _DO_THROW("Given object is not an instance of the class this method was declared in"); + /* Returns from this function */ + } + + zend_create_closure(return_value, mptr, mptr->common.scope, obj TSRMLS_CC); + } +} +/* }}} */ + /* {{{ proto public mixed ReflectionMethod::invoke(mixed object, mixed* args) U Invokes the method. */ ZEND_METHOD(reflection_method, invoke) @@ -4781,6 +4824,7 @@ ZEND_ME(reflection_function, __toString, NULL, 0) ZEND_ME(reflection_function, export, arginfo_reflection_function_export, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC) ZEND_ME(reflection_function, isDisabled, NULL, 0) + ZEND_ME(reflection_function, getClosure, NULL, 0) ZEND_ME(reflection_function, invoke, arginfo_reflection_function_invoke, 0) ZEND_ME(reflection_function, invokeArgs, arginfo_reflection_function_invokeArgs, 0) {NULL, NULL, NULL} @@ -4824,6 +4868,7 @@ ZEND_ME(reflection_method, isConstructor, NULL, 0) ZEND_ME(reflection_method, isDestructor, NULL, 0) ZEND_ME(reflection_method, getModifiers, NULL, 0) + ZEND_ME(reflection_method, getClosure, NULL, 0) ZEND_ME(reflection_method, invoke, arginfo_reflection_method_invoke, 0) ZEND_ME(reflection_method, invokeArgs, arginfo_reflection_method_invokeArgs, 0) ZEND_ME(reflection_method, getDeclaringClass, NULL, 0) @@ -5210,7 +5255,7 @@ php_info_print_table_start(); php_info_print_table_header(2, "Reflection", "enabled"); - php_info_print_table_row(2, "Version", "$Id: php_reflection.c,v 1.298 2008/06/27 06:43:38 dmitry Exp $"); + php_info_print_table_row(2, "Version", "$Id: php_reflection.c,v 1.299 2008/07/08 07:05:04 dmitry Exp $"); php_info_print_table_end(); } /* }}} */ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_closures.c?view=markup&rev=1.1 Index: ZendEngine2/zend_closures.c +++ ZendEngine2/zend_closures.c /* +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ | Copyright (c) 1998-2008 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | 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 | | [EMAIL PROTECTED] so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Christian Seiler <[EMAIL PROTECTED]> | | Dmitry Stogov <[EMAIL PROTECTED]> | +----------------------------------------------------------------------+ */ /* $Id: zend_closures.c,v 1.1 2008/07/08 07:05:03 dmitry Exp $ */ #include "zend.h" #include "zend_API.h" #include "zend_closures.h" #include "zend_objects.h" #include "zend_objects_API.h" #include "zend_globals.h" typedef struct _zend_closure { zend_object std; zend_function func; zval *this_ptr; } zend_closure; static zend_class_entry *zend_ce_closure; static zend_object_handlers closure_handlers; ZEND_METHOD(Closure, __invoke) /* {{{ */ { 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); zend_error(E_ERROR, "Cannot get arguments for calling closure"); RETURN_FALSE; } if (!return_value_ptr) { return_value_ptr = &closure_result_ptr; } if (call_user_function_ex(CG(function_table), NULL, this_ptr, return_value_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) { efree(arguments); RETURN_FALSE; } efree(arguments); if (closure_result_ptr) { RETVAL_ZVAL(closure_result_ptr, 1, 1); } } /* }}} */ const static zend_function_entry closure_functions[] = { /* {{{ */ ZEND_ME(Closure, __invoke, NULL, 0) {NULL, NULL, NULL} }; /* }}} */ static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */ { zend_error(E_ERROR, "Instantiation of 'Closure' is not allowed"); 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)); } /* }}} */ static int zend_closure_cast_object_tostring(zval *readobj, zval *writeobj, int type, void *extra TSRMLS_DC) /* {{{ */ { zend_class_entry *ce; switch (type) { case IS_STRING: case IS_UNICODE: INIT_PZVAL(writeobj); ZVAL_ASCII_STRINGL(writeobj, "Closure object", sizeof("Closure object")-1, ZSTR_DUPLICATE); return SUCCESS; default: ce = Z_OBJCE_P(readobj); zend_error(E_NOTICE, "Object of class %v could not be converted to %s", ce->name, zend_get_type_by_const(type)); INIT_PZVAL(writeobj); Z_TYPE_P(writeobj) = IS_NULL; break; } return FAILURE; } /* }}} */ 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); } if (closure->this_ptr) { zval_ptr_dtor(&closure->this_ptr); } 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); 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; return object; } /* }}} */ void zend_register_closure_ce(TSRMLS_D) /* {{{ */ { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "Closure", closure_functions); 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; memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); closure_handlers.get_constructor = zend_closure_get_constructor; closure_handlers.compare_objects = zend_closure_compare_objects; closure_handlers.cast_object = zend_closure_cast_object_tostring; closure_handlers.clone_obj = NULL; } /* }}} */ static int zval_copy_static_var(zval **p, int num_args, va_list args, zend_hash_key *key) /* {{{ */ { HashTable *target = va_arg(args, HashTable*); zend_bool is_ref; TSRMLS_FETCH(); if (Z_TYPE_PP(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) { TSRMLS_FETCH(); is_ref = Z_TYPE_PP(p) & IS_LEXICAL_REF; if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } if (zend_u_hash_quick_find(EG(active_symbol_table), key->type, key->arKey, key->nKeyLength, key->h, (void **) &p) == FAILURE) { if (is_ref) { zval *tmp; ALLOC_INIT_ZVAL(tmp); Z_SET_ISREF_P(tmp); zend_u_hash_quick_add(EG(active_symbol_table), key->type, key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), (void**)&p); } else { p = &EG(uninitialized_zval_ptr); zend_error(E_NOTICE,"Undefined variable: %s", key->arKey); } } else { if (is_ref) { SEPARATE_ZVAL_TO_MAKE_IS_REF(p); } else if (Z_ISREF_PP(p)) { SEPARATE_ZVAL(p); } } } if (zend_u_hash_quick_add(target, key->type, key->arKey, key->nKeyLength, key->h, p, sizeof(zval*), NULL) == SUCCESS) { Z_ADDREF_PP(p); } return ZEND_HASH_APPLY_KEEP; } /* }}} */ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zval *this_ptr TSRMLS_DC) /* {{{ */ { zend_closure *closure; object_init_ex(res, zend_ce_closure); closure = (zend_closure *)zend_object_store_get_object(res TSRMLS_CC); closure->func = *func; if (closure->func.type == ZEND_USER_FUNCTION) { if (closure->func.op_array.static_variables) { HashTable *static_variables = closure->func.op_array.static_variables; ALLOC_HASHTABLE(closure->func.op_array.static_variables); zend_u_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); zend_hash_apply_with_arguments(static_variables, (apply_func_args_t)zval_copy_static_var, 1, closure->func.op_array.static_variables); } (*closure->func.op_array.refcount)++; } 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->this_ptr = NULL; } } else { closure->this_ptr = NULL; } } /* }}} */ 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) /* {{{ */ { zstr key; zend_uchar utype = UG(unicode)?IS_UNICODE:IS_STRING; if (utype == IS_UNICODE) { key.u = USTR_MAKE("__invoke"); } else { key.s = "__invoke"; } if (Z_TYPE_P(obj) == IS_OBJECT) { zend_class_entry *ce = Z_OBJCE_P(obj); if (ce == zend_ce_closure) { zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC); *fptr_ptr = &closure->func; if (closure->this_ptr) { if (zobj_ptr) { *zobj_ptr = closure->this_ptr; } if (zobj_ptr_ptr) { *zobj_ptr_ptr = &closure->this_ptr; } *ce_ptr = Z_OBJCE_P(closure->this_ptr); } else { if (zobj_ptr) { *zobj_ptr = NULL; } if (zobj_ptr_ptr) { *zobj_ptr_ptr = NULL; } *ce_ptr = closure->func.common.scope; } if (utype == IS_UNICODE) { efree(key.u); } return SUCCESS; } else if (zend_u_hash_find(&ce->function_table, utype, key, sizeof("__invoke"), (void**)fptr_ptr) == SUCCESS) { *ce_ptr = ce; if ((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC) { if (zobj_ptr) { *zobj_ptr = NULL; } if (zobj_ptr_ptr) { *zobj_ptr_ptr = NULL; } } else { if (zobj_ptr) { *zobj_ptr = obj; } if (zobj_ptr_ptr) { *zobj_ptr_ptr = NULL; } } if (utype == IS_UNICODE) { efree(key.u); } return SUCCESS; } } if (utype == IS_UNICODE) { efree(key.u); } return FAILURE; } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode: t * End: */ http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_closures.h?view=markup&rev=1.1 Index: ZendEngine2/zend_closures.h +++ ZendEngine2/zend_closures.h /* +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ | Copyright (c) 1998-2008 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | 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 | | [EMAIL PROTECTED] so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Christian Seiler <[EMAIL PROTECTED]> | | Dmitry Stogov <[EMAIL PROTECTED]> | +----------------------------------------------------------------------+ */ /* $Id: zend_closures.h,v 1.1 2008/07/08 07:05:03 dmitry Exp $ */ #ifndef ZEND_CLOSURES_H #define ZEND_CLOSURES_H BEGIN_EXTERN_C() void zend_register_closure_ce(TSRMLS_D); 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); END_EXTERN_C() #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode: t * End: */ http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_001.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_001.phpt +++ ZendEngine2/tests/closure_001.phpt --TEST-- Closure 001: Lambda without lexical variables --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php $lambda1 = function () { echo "Hello World!\n"; }; $lambda2 = function ($x) { echo "Hello $x!\n"; }; var_dump(is_callable($lambda1)); var_dump(is_callable($lambda2)); $lambda1(); $lambda2("Universe"); call_user_func($lambda1); call_user_func($lambda2, "Universe"); echo "Done\n"; ?> --EXPECT-- bool(true) bool(true) Hello World! Hello Universe! Hello World! Hello Universe! Done http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_002.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_002.phpt +++ ZendEngine2/tests/closure_002.phpt --TEST-- Closure 002: Lambda with lexical variables (global scope) --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php $x = 4; $lambda1 = function () use ($x) { echo "$x\n"; }; $lambda2 = function () use (&$x) { echo "$x\n"; }; $lambda1(); $lambda2(); $x++; $lambda1(); $lambda2(); echo "Done\n"; ?> --EXPECT-- 4 4 4 5 Done http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_003.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_003.phpt +++ ZendEngine2/tests/closure_003.phpt --TEST-- Closure 003: Lambda with lexical variables (local scope) --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php function run () { $x = 4; $lambda1 = function () use ($x) { echo "$x\n"; }; $lambda2 = function () use (&$x) { echo "$x\n"; }; $lambda1(); $lambda2(); $x++; $lambda1(); $lambda2(); } run(); echo "Done\n"; ?> --EXPECT-- 4 4 4 5 Done http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_004.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_004.phpt +++ ZendEngine2/tests/closure_004.phpt --TEST-- Closure 004: Lambda with lexical variables (scope lifetime) --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php function run () { $x = 4; $lambda1 = function () use ($x) { echo "$x\n"; }; $lambda2 = function () use (&$x) { echo "$x\n"; $x++; }; return array($lambda1, $lambda2); } list ($lambda1, $lambda2) = run(); $lambda1(); $lambda2(); $lambda1(); $lambda2(); echo "Done\n"; ?> --EXPECT-- 4 4 4 5 Done http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_005.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_005.phpt +++ ZendEngine2/tests/closure_005.phpt --TEST-- Closure 005: Lambda inside class, lifetime of $this --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php class A { private $x; function __construct($x) { $this->x = $x; } function __destruct() { echo "Destroyed\n"; } function getIncer($val) { return function() use ($val) { $this->x += $val; }; } function getPrinter() { return function() { echo $this->x."\n"; }; } function getError() { return static function() { echo $this->x."\n"; }; } function printX() { echo $this->x."\n"; } } $a = new A(3); $incer = $a->getIncer(2); $printer = $a->getPrinter(); $error = $a->getError(); $a->printX(); $printer(); $incer(); $a->printX(); $printer(); unset($a); $incer(); $printer(); unset($incer); $printer(); unset($printer); $error(); echo "Done\n"; ?> --EXPECTF-- 3 3 5 5 7 7 Destroyed Fatal error: Using $this when not in object context in %sclosure_005.php on line 28 http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_006.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_006.phpt +++ ZendEngine2/tests/closure_006.phpt --TEST-- Closure 006: Nested lambdas --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php $getClosure = function ($v) { return function () use ($v) { echo "Hello World: $v!\n"; }; }; $closure = $getClosure (2); $closure (); echo "Done\n"; ?> --EXPECT-- Hello World: 2! Done http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_007.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_007.phpt +++ ZendEngine2/tests/closure_007.phpt --TEST-- Closure 007: Nested lambdas in classes --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php class A { private $x = 0; function getClosureGetter () { return function () { return function () { $this->x++; }; }; } function printX () { echo $this->x."\n"; } } $a = new A; $a->printX(); $getClosure = $a->getClosureGetter(); $a->printX(); $closure = $getClosure(); $a->printX(); $closure(); $a->printX(); echo "Done\n"; ?> --EXPECT-- 0 0 0 1 Done http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_008.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_008.phpt +++ ZendEngine2/tests/closure_008.phpt --TEST-- Closure 008: Use in preg_replace() --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php function replace_spaces($text) { $lambda = function ($matches) { return str_replace(' ', ' ', $matches[1]).' '; }; return preg_replace_callback('/( +) /', $lambda, $text); } echo replace_spaces("1 2 3\n"); echo replace_spaces("1 2 3\n"); echo replace_spaces("1 2 3\n"); echo "Done\n"; ?> --EXPECT-- 1 2 3 1 2 3 1 2 3 Done http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_009.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_009.phpt +++ ZendEngine2/tests/closure_009.phpt --TEST-- Closure 009: Use in preg_replace() --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php $a = 1; $x = function ($x) use ($a) { static $n = 0; $n++; $a = $n.':'.$a; echo $x.':'.$a."\n"; }; $y = function ($x) use (&$a) { static $n = 0; $n++; $a = $n.':'.$a; echo $x.':'.$a."\n"; }; $x(1); $x(2); $x(3); $y(4); $y(5); $y(6); ?> --EXPECT-- 1:1:1 2:2:1 3:3:1 4:1:1 5:2:1:1 6:3:2:1:1 http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_010.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_010.phpt +++ ZendEngine2/tests/closure_010.phpt --TEST-- Closure 010: Closure calls itself --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php $i = 3; $lambda = function ($lambda) use (&$i) { if ($i==0) return; echo $i--."\n"; $lambda($lambda); }; $lambda($lambda); echo "$i\n"; ?> --EXPECT-- 3 2 1 0 http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_011.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_011.phpt +++ ZendEngine2/tests/closure_011.phpt --TEST-- Closure 011: Lexical copies not static in closure --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php $i = 1; $lambda = function () use ($i) { return ++$i; }; $lambda(); echo $lambda()."\n"; //early prototypes gave 3 here because $i was static in $lambda ?> --EXPECT-- 2 http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_012.phpt?view=markup&rev=1.1 Index: ZendEngine2/tests/closure_012.phpt +++ ZendEngine2/tests/closure_012.phpt --TEST-- Closure 012: Undefined lexical variables --SKIPIF-- <?php if (!class_exists('Closure')) die('skip Closure support is needed'); ?> --FILE-- <?php $lambda = function () use ($i) { return ++$i; }; $lambda(); $lambda(); var_dump($i); $lambda = function () use (&$i) { return ++$i; }; $lambda(); $lambda(); var_dump($i); ?> --EXPECTF-- Notice: Undefined variable: i in %sclosure_012.php on line 2 Notice: Undefined variable: i in %sclosure_012.php on line 7 NULL int(2)
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php