dmitry          Mon Jul 14 09:49:05 2008 UTC

  Added files:                 (Branch: PHP_5_3)
    /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 
                        closure_013.phpt closure_014.phpt 
                        closure_015.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 support for lambda functions and closures
  
  
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.965.2.200&r2=1.2027.2.547.2.965.2.201&diff_format=u
Index: php-src/NEWS
diff -u php-src/NEWS:1.2027.2.547.2.965.2.200 
php-src/NEWS:1.2027.2.547.2.965.2.201
--- php-src/NEWS:1.2027.2.547.2.965.2.200       Mon Jul 14 06:44:05 2008
+++ php-src/NEWS        Mon Jul 14 09:48:58 2008
@@ -17,6 +17,7 @@
 - Changed mhash to be a wrapper layer around the hash extension. (Scott)
 
 - Improved PHP syntax and semantics:
+  . Added lambda functions and closures (Christian Seiler, Dmitry)
   . Added "jump label" operator (limited "goto"). (Dmitry, Sara)
   . Added NOWDOC syntax. (Gwynne Raskind, Stas, Dmitry)
   . Added HEREDOC syntax with double quotes. (Lars Strojny, Felipe)
http://cvs.php.net/viewvc.cgi/php-src/configure.in?r1=1.579.2.52.2.77.2.20&r2=1.579.2.52.2.77.2.21&diff_format=u
Index: php-src/configure.in
diff -u php-src/configure.in:1.579.2.52.2.77.2.20 
php-src/configure.in:1.579.2.52.2.77.2.21
--- php-src/configure.in:1.579.2.52.2.77.2.20   Mon Jun  2 16:58:19 2008
+++ php-src/configure.in        Mon Jul 14 09:48:58 2008
@@ -1,4 +1,4 @@
-## $Id: configure.in,v 1.579.2.52.2.77.2.20 2008/06/02 16:58:19 helly Exp $ 
-*- autoconf -*-
+## $Id: configure.in,v 1.579.2.52.2.77.2.21 2008/07/14 09:48:58 dmitry Exp $ 
-*- autoconf -*-
 dnl ## Process this file with autoconf to produce a configure script.
 
 divert(1)
@@ -1403,7 +1403,8 @@
     zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \
     zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \
     zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \
-    zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c 
zend_gc.c)
+    zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.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.57.2.1.2.1.2.1&r2=1.57.2.1.2.1.2.2&diff_format=u
Index: ZendEngine2/Makefile.am
diff -u ZendEngine2/Makefile.am:1.57.2.1.2.1.2.1 
ZendEngine2/Makefile.am:1.57.2.1.2.1.2.2
--- ZendEngine2/Makefile.am:1.57.2.1.2.1.2.1    Sun Mar 16 21:05:33 2008
+++ ZendEngine2/Makefile.am     Mon Jul 14 09:48:58 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_closures.c
 
 libZend_la_LDFLAGS =
 libZend_la_LIBADD = @ZEND_EXTRA_LIBS@
http://cvs.php.net/viewvc.cgi/ZendEngine2/Zend.dsp?r1=1.25.2.1.2.1&r2=1.25.2.1.2.1.2.1&diff_format=u
Index: ZendEngine2/Zend.dsp
diff -u ZendEngine2/Zend.dsp:1.25.2.1.2.1 ZendEngine2/Zend.dsp:1.25.2.1.2.1.2.1
--- ZendEngine2/Zend.dsp:1.25.2.1.2.1   Tue Dec  5 08:07:57 2006
+++ ZendEngine2/Zend.dsp        Mon Jul 14 09:48:58 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.47.2.1.2.2&r2=1.47.2.1.2.2.2.1&diff_format=u
Index: ZendEngine2/ZendTS.dsp
diff -u ZendEngine2/ZendTS.dsp:1.47.2.1.2.2 
ZendEngine2/ZendTS.dsp:1.47.2.1.2.2.2.1
--- ZendEngine2/ZendTS.dsp:1.47.2.1.2.2 Tue Dec  5 08:07:57 2006
+++ ZendEngine2/ZendTS.dsp      Mon Jul 14 09:48:58 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.293.2.11.2.9.2.23&r2=1.293.2.11.2.9.2.24&diff_format=u
Index: ZendEngine2/zend.h
diff -u ZendEngine2/zend.h:1.293.2.11.2.9.2.23 
ZendEngine2/zend.h:1.293.2.11.2.9.2.24
--- ZendEngine2/zend.h:1.293.2.11.2.9.2.23      Fri Jun 27 18:44:39 2008
+++ ZendEngine2/zend.h  Mon Jul 14 09:48:58 2008
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend.h,v 1.293.2.11.2.9.2.23 2008/06/27 18:44:39 stas Exp $ */
+/* $Id: zend.h,v 1.293.2.11.2.9.2.24 2008/07/14 09:48:58 dmitry Exp $ */
 
 #ifndef ZEND_H
 #define ZEND_H
@@ -518,6 +518,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.296.2.27.2.34.2.38&r2=1.296.2.27.2.34.2.39&diff_format=u
Index: ZendEngine2/zend_API.c
diff -u ZendEngine2/zend_API.c:1.296.2.27.2.34.2.38 
ZendEngine2/zend_API.c:1.296.2.27.2.34.2.39
--- ZendEngine2/zend_API.c:1.296.2.27.2.34.2.38 Thu Jun  5 18:53:06 2008
+++ ZendEngine2/zend_API.c      Mon Jul 14 09:48:59 2008
@@ -18,7 +18,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_API.c,v 1.296.2.27.2.34.2.38 2008/06/05 18:53:06 felipe Exp $ */
+/* $Id: zend_API.c,v 1.296.2.27.2.34.2.39 2008/07/14 09:48:59 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>
@@ -2615,6 +2616,16 @@
                        }
                        return 0;
 
+               case IS_OBJECT:
+                       if (zend_get_closure(callable, ce_ptr, fptr_ptr, NULL, 
zobj_ptr_ptr TSRMLS_CC) == SUCCESS) {
+                               if (callable_name) {
+                                       *callable_name_len = 
strlen((*fptr_ptr)->common.function_name);
+                                       *callable_name = 
estrndup((*fptr_ptr)->common.function_name, *callable_name_len);
+                               }                                               
                        
+                               return 1;
+                       }
+                       /* break missing intentionally */
+
                default:
                        if (callable_name) {
                                zval expr_copy;
http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_compile.c?r1=1.647.2.27.2.41.2.70&r2=1.647.2.27.2.41.2.71&diff_format=u
Index: ZendEngine2/zend_compile.c
diff -u ZendEngine2/zend_compile.c:1.647.2.27.2.41.2.70 
ZendEngine2/zend_compile.c:1.647.2.27.2.41.2.71
--- ZendEngine2/zend_compile.c:1.647.2.27.2.41.2.70     Sun Jun 29 08:21:34 2008
+++ ZendEngine2/zend_compile.c  Mon Jul 14 09:48:59 2008
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_compile.c,v 1.647.2.27.2.41.2.70 2008/06/29 08:21:34 hirokawa Exp 
$ */
+/* $Id: zend_compile.c,v 1.647.2.27.2.41.2.71 2008/07/14 09:48:59 dmitry Exp $ 
*/
 
 #include <zend_language_parser.h>
 #include "zend.h"
@@ -1401,6 +1401,33 @@
        CG(labels) = NULL;
 }
 
+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_STRINGL(&function_name.u.constant, "lambda", sizeof("lambda")-1, 
1);
+
+       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 = &current_op_array->opcodes[current_op_number];
+       current_op->opcode = ZEND_DECLARE_LAMBDA_FUNCTION;
+       zval_dtor(&current_op->op2.u.constant);
+       ZVAL_LONG(&current_op->op2.u.constant, 
zend_hash_func(Z_STRVAL(current_op->op1.u.constant), 
Z_STRLEN(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);
@@ -4155,13 +4182,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) {
@@ -4169,12 +4196,39 @@
        }
        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);
+       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_STRLEN(varname->u.constant) == sizeof("this") - 1 &&
+           memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this") - 1) 
== 0) {
+               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.316.2.8.2.12.2.25&r2=1.316.2.8.2.12.2.26&diff_format=u
Index: ZendEngine2/zend_compile.h
diff -u ZendEngine2/zend_compile.h:1.316.2.8.2.12.2.25 
ZendEngine2/zend_compile.h:1.316.2.8.2.12.2.26
--- ZendEngine2/zend_compile.h:1.316.2.8.2.12.2.25      Wed Jun 11 13:18:39 2008
+++ ZendEngine2/zend_compile.h  Mon Jul 14 09:49:00 2008
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_compile.h,v 1.316.2.8.2.12.2.25 2008/06/11 13:18:39 dmitry Exp $ 
*/
+/* $Id: zend_compile.h,v 1.316.2.8.2.12.2.26 2008/07/14 09:49:00 dmitry Exp $ 
*/
 
 #ifndef ZEND_COMPILE_H
 #define ZEND_COMPILE_H
@@ -151,6 +151,8 @@
 /* class implement interface(s) flag */
 #define ZEND_ACC_IMPLEMENT_INTERFACES 0x80000
 
+#define ZEND_ACC_CLOSURE              0x100000
+
 
 char *zend_visibility_string(zend_uint fn_flags);
 
@@ -429,6 +431,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);
@@ -614,7 +619,8 @@
 #define ZEND_FETCH_LOCAL                       1
 #define ZEND_FETCH_STATIC                      2
 #define ZEND_FETCH_STATIC_MEMBER       3
-#define ZEND_FETCH_GLOBAL_LOCK 4
+#define ZEND_FETCH_GLOBAL_LOCK         4
+#define ZEND_FETCH_LEXICAL                     5
 
 
 /* class fetches */
http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_default_classes.c?r1=1.59.2.2.2.1.2.1&r2=1.59.2.2.2.1.2.2&diff_format=u
Index: ZendEngine2/zend_default_classes.c
diff -u ZendEngine2/zend_default_classes.c:1.59.2.2.2.1.2.1 
ZendEngine2/zend_default_classes.c:1.59.2.2.2.1.2.2
--- ZendEngine2/zend_default_classes.c:1.59.2.2.2.1.2.1 Mon Dec 31 07:17:04 2007
+++ ZendEngine2/zend_default_classes.c  Mon Jul 14 09:49:00 2008
@@ -17,13 +17,14 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_default_classes.c,v 1.59.2.2.2.1.2.1 2007/12/31 07:17:04 
sebastian Exp $ */
+/* $Id: zend_default_classes.c,v 1.59.2.2.2.1.2.2 2008/07/14 09:49:00 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_interfaces(TSRMLS_C);
        zend_register_default_exception(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.716.2.12.2.24.2.31&r2=1.716.2.12.2.24.2.32&diff_format=u
Index: ZendEngine2/zend_execute.c
diff -u ZendEngine2/zend_execute.c:1.716.2.12.2.24.2.31 
ZendEngine2/zend_execute.c:1.716.2.12.2.24.2.32
--- ZendEngine2/zend_execute.c:1.716.2.12.2.24.2.31     Tue Jul  1 13:20:48 2008
+++ ZendEngine2/zend_execute.c  Mon Jul 14 09:49:00 2008
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_execute.c,v 1.716.2.12.2.24.2.31 2008/07/01 13:20:48 dmitry Exp $ 
*/
+/* $Id: zend_execute.c,v 1.716.2.12.2.24.2.32 2008/07/14 09:49:00 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"
 
 /* Virtual current working directory support */
http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_execute_API.c?r1=1.331.2.20.2.24.2.42&r2=1.331.2.20.2.24.2.43&diff_format=u
Index: ZendEngine2/zend_execute_API.c
diff -u ZendEngine2/zend_execute_API.c:1.331.2.20.2.24.2.42 
ZendEngine2/zend_execute_API.c:1.331.2.20.2.24.2.43
--- ZendEngine2/zend_execute_API.c:1.331.2.20.2.24.2.42 Thu Jun  5 18:50:29 2008
+++ ZendEngine2/zend_execute_API.c      Mon Jul 14 09:49:00 2008
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_execute_API.c,v 1.331.2.20.2.24.2.42 2008/06/05 18:50:29 felipe 
Exp $ */
+/* $Id: zend_execute_API.c,v 1.331.2.20.2.24.2.43 2008/07/14 09:49:00 dmitry 
Exp $ */
 
 #include <stdio.h>
 #include <signal.h>
@@ -30,6 +30,7 @@
 #include "zend_constants.h"
 #include "zend_extensions.h"
 #include "zend_exceptions.h"
+#include "zend_closures.h"
 #include "zend_vm.h"
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
@@ -826,7 +827,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) {
                        return FAILURE;
                }
 
@@ -935,6 +940,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.160.2.4.2.8.2.21&r2=1.160.2.4.2.8.2.22&diff_format=u
Index: ZendEngine2/zend_language_parser.y
diff -u ZendEngine2/zend_language_parser.y:1.160.2.4.2.8.2.21 
ZendEngine2/zend_language_parser.y:1.160.2.4.2.8.2.22
--- ZendEngine2/zend_language_parser.y:1.160.2.4.2.8.2.21       Sun Jun  8 
09:38:47 2008
+++ ZendEngine2/zend_language_parser.y  Mon Jul 14 09:49:00 2008
@@ -18,7 +18,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_language_parser.y,v 1.160.2.4.2.8.2.21 2008/06/08 09:38:47 stas 
Exp $ */
+/* $Id: zend_language_parser.y,v 1.160.2.4.2.8.2.22 2008/07/14 09:49:00 dmitry 
Exp $ */
 
 /*
  * LALR shift/reduce conflicts and how they are resolved:
@@ -302,7 +302,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); }
 ;
 
@@ -510,8 +510,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); }
 ;
 
 
@@ -643,10 +643,30 @@
        |       T_ARRAY '(' array_pair_list ')' { $$ = $3; }
        |       '`' encaps_list '`' { zend_do_shell_exec(&$$, &$2 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.59.2.29.2.48.2.58&r2=1.59.2.29.2.48.2.59&diff_format=u
Index: ZendEngine2/zend_vm_def.h
diff -u ZendEngine2/zend_vm_def.h:1.59.2.29.2.48.2.58 
ZendEngine2/zend_vm_def.h:1.59.2.29.2.48.2.59
--- ZendEngine2/zend_vm_def.h:1.59.2.29.2.48.2.58       Wed Jun 11 13:18:39 2008
+++ ZendEngine2/zend_vm_def.h   Mon Jul 14 09:49:00 2008
@@ -18,7 +18,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_vm_def.h,v 1.59.2.29.2.48.2.58 2008/06/11 13:18:39 dmitry Exp $ */
+/* $Id: zend_vm_def.h,v 1.59.2.29.2.48.2.59 2008/07/14 09:49:00 dmitry Exp $ */
 
 /* If you change this file, please regenerate the zend_vm_execute.h and
  * zend_vm_opcodes.h files by running:
@@ -2029,6 +2029,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) {
                        zend_error_noreturn(E_ERROR, "Function name must be a 
string");
                }
@@ -4327,4 +4336,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_hash_quick_find(EG(function_table), 
Z_STRVAL(opline->op1.u.constant), Z_STRLEN(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.62.2.30.2.49.2.58&r2=1.62.2.30.2.49.2.59&diff_format=u
Index: ZendEngine2/zend_vm_execute.h
diff -u ZendEngine2/zend_vm_execute.h:1.62.2.30.2.49.2.58 
ZendEngine2/zend_vm_execute.h:1.62.2.30.2.49.2.59
--- ZendEngine2/zend_vm_execute.h:1.62.2.30.2.49.2.58   Wed Jun 11 13:18:39 2008
+++ ZendEngine2/zend_vm_execute.h       Mon Jul 14 09:49:00 2008
@@ -747,6 +747,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) {
                        zend_error_noreturn(E_ERROR, "Function name must be a 
string");
                }
@@ -935,6 +944,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) {
                        zend_error_noreturn(E_ERROR, "Function name must be a 
string");
                }
@@ -1031,6 +1049,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) {
                        zend_error_noreturn(E_ERROR, "Function name must be a 
string");
                }
@@ -1155,6 +1182,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) {
                        zend_error_noreturn(E_ERROR, "Function name must be a 
string");
                }
@@ -2875,6 +2911,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_hash_quick_find(EG(function_table), 
Z_STRVAL(opline->op1.u.constant), Z_STRLEN(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);
@@ -33508,6 +33559,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.42.2.17.2.1.2.6&r2=1.42.2.17.2.1.2.7&diff_format=u
Index: ZendEngine2/zend_vm_opcodes.h
diff -u ZendEngine2/zend_vm_opcodes.h:1.42.2.17.2.1.2.6 
ZendEngine2/zend_vm_opcodes.h:1.42.2.17.2.1.2.7
--- ZendEngine2/zend_vm_opcodes.h:1.42.2.17.2.1.2.6     Fri Mar 28 14:35:01 2008
+++ ZendEngine2/zend_vm_opcodes.h       Mon Jul 14 09:49:02 2008
@@ -152,3 +152,4 @@
 #define ZEND_HANDLE_EXCEPTION                149
 #define ZEND_USER_OPCODE                     150
 #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.168.2.9.2.21.2.17&r2=1.168.2.9.2.21.2.18&diff_format=u
Index: php-src/ext/pcre/php_pcre.c
diff -u php-src/ext/pcre/php_pcre.c:1.168.2.9.2.21.2.17 
php-src/ext/pcre/php_pcre.c:1.168.2.9.2.21.2.18
--- php-src/ext/pcre/php_pcre.c:1.168.2.9.2.21.2.17     Mon Jun 30 17:14:48 2008
+++ php-src/ext/pcre/php_pcre.c Mon Jul 14 09:49:02 2008
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: php_pcre.c,v 1.168.2.9.2.21.2.17 2008/06/30 17:14:48 felipe Exp $ */
+/* $Id: php_pcre.c,v 1.168.2.9.2.21.2.18 2008/07/14 09:49:02 dmitry Exp $ */
 
 #include "php.h"
 #include "php_ini.h"
@@ -1312,7 +1312,7 @@
        }
 
        SEPARATE_ZVAL(replace);
-       if (Z_TYPE_PP(replace) != IS_ARRAY)
+       if (Z_TYPE_PP(replace) != IS_ARRAY && (Z_TYPE_PP(replace) != IS_OBJECT 
|| !is_callable_replace))
                convert_to_string_ex(replace);
        if (is_callable_replace) {
                if (!zend_is_callable(*replace, 0, &callback_name)) {
http://cvs.php.net/viewvc.cgi/php-src/ext/reflection/php_reflection.c?r1=1.164.2.33.2.45.2.18&r2=1.164.2.33.2.45.2.19&diff_format=u
Index: php-src/ext/reflection/php_reflection.c
diff -u php-src/ext/reflection/php_reflection.c:1.164.2.33.2.45.2.18 
php-src/ext/reflection/php_reflection.c:1.164.2.33.2.45.2.19
--- php-src/ext/reflection/php_reflection.c:1.164.2.33.2.45.2.18        Fri Jun 
27 06:43:21 2008
+++ php-src/ext/reflection/php_reflection.c     Mon Jul 14 09:49:03 2008
@@ -20,7 +20,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: php_reflection.c,v 1.164.2.33.2.45.2.18 2008/06/27 06:43:21 dmitry Exp 
$ */
+/* $Id: php_reflection.c,v 1.164.2.33.2.45.2.19 2008/07/14 09:49:03 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"
 
 /* Undefine "getParameters" macro defined in "main/php3_compat.h" */
 #ifdef getParameters
@@ -1562,6 +1563,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)
    Invokes the function */
 ZEND_METHOD(reflection_function, invoke)
@@ -2290,6 +2305,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)
    Invokes the method. */
 ZEND_METHOD(reflection_method, invoke)
@@ -4641,6 +4684,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}
@@ -4684,6 +4728,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)
@@ -5069,7 +5114,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.164.2.33.2.45.2.18 2008/06/27 06:43:21 dmitry Exp $");
+       php_info_print_table_row(2, "Version", "$Id: php_reflection.c,v 
1.164.2.33.2.45.2.19 2008/07/14 09:49:03 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(' ', '&nbsp;', $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&nbsp; 2&nbsp; 3
1&nbsp;&nbsp; 2&nbsp;&nbsp; 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)


http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_013.phpt?view=markup&rev=1.1
Index: ZendEngine2/tests/closure_013.phpt
+++ ZendEngine2/tests/closure_013.phpt
--TEST--
Closure 013: __invoke() on temporary result
--SKIPIF--
<?php 
        if (!class_exists('Closure')) die('skip Closure support is needed');
?>
--FILE--
<?php
class Foo {
        function __invoke() {
                echo "Hello World!\n";
        }
}

function foo() {
        return function() {
                echo "Hello World!\n";
        };
}
$test = new Foo;
$test->__invoke();
$test = foo();
$test->__invoke();
$test = foo()->__invoke();
?>
--EXPECT--
Hello World!
Hello World!
Hello World!

http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_014.phpt?view=markup&rev=1.1
Index: ZendEngine2/tests/closure_014.phpt
+++ ZendEngine2/tests/closure_014.phpt
--TEST--
Closure 014: return by value/reference
--SKIPIF--
<?php 
        if (!class_exists('Closure')) die('skip Closure support is needed');
?>
--FILE--
<?php
class C1 {
        function __invoke() {
                return 0;
        }
}
class C2 {
        function &__invoke(&$a) {
                return $a;
        }
}
class C3 {
        function __invoke() {
        }
}

$x = new C1();
var_dump($x());
var_dump($x->__invoke());
$x();
$x->__invoke();
$x = function() {
        return 0;
};
var_dump($x());
var_dump($x->__invoke());
$x();
$x->__invoke();

$x = new C2();
$a = $b = $c = $d = 1;
$e =& $x($a);
$e = 2;
var_dump($a);
$e =& $x->__invoke($b);
$e = 3;
var_dump($b);
$x($b);
$x->__invoke($b);
$x = function & (&$a) {
        return $a;
};
$e =& $x($c);
$e = 4;
var_dump($c);
$e =& $x->__invoke($d);
$e = 5;
var_dump($d);
$x($d);
$x->__invoke($d);

$x = new C3();
var_dump($x());
var_dump($x->__invoke());
$x();
$x->__invoke();
$x = function() {
};
var_dump($x());
var_dump($x->__invoke());
$x();
$x->__invoke();
?>
--EXPECT--
int(0)
int(0)
int(0)
int(0)
int(2)
int(3)
int(4)
int(5)
NULL
NULL
NULL
NULL

http://cvs.php.net/viewvc.cgi/ZendEngine2/tests/closure_015.phpt?view=markup&rev=1.1
Index: ZendEngine2/tests/closure_015.phpt
+++ ZendEngine2/tests/closure_015.phpt
--TEST--
Closure 015: converting to string/unicode
--FILE--
<?php
$x = function() { return 1; };
print (string) $x;
print "\n";
print (unicode) $x;
print "\n";
print $x;
print "\n";
?>
--EXPECT--
Closure object
Closure object
Closure object

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to