32 changed files with 1040 additions and 13 deletions
-
1NEWS
-
2Zend/Makefile.am
-
4Zend/Zend.dsp
-
4Zend/ZendTS.dsp
-
34Zend/tests/closure_001.phpt
-
33Zend/tests/closure_002.phpt
-
37Zend/tests/closure_003.phpt
-
39Zend/tests/closure_004.phpt
-
78Zend/tests/closure_005.phpt
-
23Zend/tests/closure_006.phpt
-
42Zend/tests/closure_007.phpt
-
26Zend/tests/closure_008.phpt
-
35Zend/tests/closure_009.phpt
-
22Zend/tests/closure_010.phpt
-
18Zend/tests/closure_011.phpt
-
28Zend/tests/closure_012.phpt
-
2Zend/zend.h
-
10Zend/zend_API.c
-
315Zend/zend_closures.c
-
42Zend/zend_closures.h
-
62Zend/zend_compile.c
-
6Zend/zend_compile.h
-
2Zend/zend_default_classes.c
-
1Zend/zend_execute.c
-
9Zend/zend_execute_API.c
-
28Zend/zend_language_parser.y
-
24Zend/zend_vm_def.h
-
76Zend/zend_vm_execute.h
-
1Zend/zend_vm_opcodes.h
-
2configure.in
-
2ext/pcre/php_pcre.c
-
45ext/reflection/php_reflection.c
@ -0,0 +1,34 @@ |
|||
--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 |
|||
@ -0,0 +1,33 @@ |
|||
--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 |
|||
@ -0,0 +1,37 @@ |
|||
--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 |
|||
@ -0,0 +1,39 @@ |
|||
--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 |
|||
@ -0,0 +1,78 @@ |
|||
--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 |
|||
@ -0,0 +1,23 @@ |
|||
--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 |
|||
@ -0,0 +1,42 @@ |
|||
--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 |
|||
@ -0,0 +1,26 @@ |
|||
--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 |
|||
@ -0,0 +1,35 @@ |
|||
--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 |
|||
@ -0,0 +1,22 @@ |
|||
--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 |
|||
@ -0,0 +1,18 @@ |
|||
--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 |
|||
@ -0,0 +1,28 @@ |
|||
--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) |
|||
|
|||
@ -0,0 +1,315 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| 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 | |
|||
| license@zend.com so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Christian Seiler <chris_se@gmx.net> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
/* $Id$ */ |
|||
|
|||
#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: |
|||
*/ |
|||
@ -0,0 +1,42 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| 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 | |
|||
| license@zend.com so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Authors: Christian Seiler <chris_se@gmx.net> | |
|||
| Dmitry Stogov <dmitry@zend.com> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
/* $Id$ */ |
|||
|
|||
#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: |
|||
*/ |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue