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