mirror of
https://github.com/php/php-src.git
synced 2024-11-27 03:44:07 +08:00
Fix LSB handling for closures
Closures will now use the called_scope from their instantiation site. If they are rebound either the class of $this is used or if no $this is provided the bound scope is used. With this change the scope for static closures can be changed back to use EG(scope) rather than EX(called_scope), thus fixing bug #69568.
This commit is contained in:
parent
dc546bdc4d
commit
d9c2959c27
25
Zend/tests/bug69568.phpt
Normal file
25
Zend/tests/bug69568.phpt
Normal file
@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Bug #69568: call a private function in closure failed
|
||||
--FILE--
|
||||
<?php
|
||||
class A {
|
||||
|
||||
private static function testprivate() {
|
||||
return 1;
|
||||
}
|
||||
public static function test() {
|
||||
return function() {
|
||||
return self::testprivate();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
}
|
||||
|
||||
$fn = B::test();
|
||||
echo $fn();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
21
Zend/tests/parent_class_name_without_parent.phpt
Normal file
21
Zend/tests/parent_class_name_without_parent.phpt
Normal file
@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Getting parent class name when there is no parent generates an error
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
trait T {
|
||||
public function f() {
|
||||
var_dump(parent::class);
|
||||
}
|
||||
}
|
||||
|
||||
class C {
|
||||
use T;
|
||||
}
|
||||
|
||||
(new C)->f();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Cannot use "parent" when current class scope has no parent in %s on line 5
|
||||
|
@ -35,9 +35,10 @@
|
||||
zend_error(E_EXCEPTION | E_ERROR, "Closure object cannot have properties")
|
||||
|
||||
typedef struct _zend_closure {
|
||||
zend_object std;
|
||||
zend_function func;
|
||||
zval this_ptr;
|
||||
zend_object std;
|
||||
zend_function func;
|
||||
zval this_ptr;
|
||||
zend_class_entry *called_scope;
|
||||
} zend_closure;
|
||||
|
||||
/* non-static since it needs to be referenced */
|
||||
@ -129,7 +130,7 @@ ZEND_METHOD(Closure, bind)
|
||||
{
|
||||
zval *newthis, *zclosure, *scope_arg = NULL;
|
||||
zend_closure *closure;
|
||||
zend_class_entry *ce;
|
||||
zend_class_entry *ce, *called_scope;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oo!|z", &zclosure, zend_ce_closure, &newthis, &scope_arg) == FAILURE) {
|
||||
RETURN_NULL();
|
||||
@ -161,7 +162,13 @@ ZEND_METHOD(Closure, bind)
|
||||
ce = closure->func.common.scope;
|
||||
}
|
||||
|
||||
zend_create_closure(return_value, &closure->func, ce, newthis);
|
||||
if (newthis) {
|
||||
called_scope = Z_OBJCE_P(newthis);
|
||||
} else {
|
||||
called_scope = ce;
|
||||
}
|
||||
|
||||
zend_create_closure(return_value, &closure->func, ce, called_scope, newthis);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -296,7 +303,8 @@ static zend_object *zend_closure_clone(zval *zobject) /* {{{ */
|
||||
zend_closure *closure = (zend_closure *)Z_OBJ_P(zobject);
|
||||
zval result;
|
||||
|
||||
zend_create_closure(&result, &closure->func, closure->func.common.scope, &closure->this_ptr);
|
||||
zend_create_closure(&result, &closure->func,
|
||||
closure->func.common.scope, closure->called_scope, &closure->this_ptr);
|
||||
return Z_OBJ(result);
|
||||
}
|
||||
/* }}} */
|
||||
@ -311,17 +319,14 @@ int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function
|
||||
|
||||
closure = (zend_closure *)Z_OBJ_P(obj);
|
||||
*fptr_ptr = &closure->func;
|
||||
*ce_ptr = closure->called_scope;
|
||||
|
||||
if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
|
||||
if (obj_ptr) {
|
||||
if (obj_ptr) {
|
||||
if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
|
||||
*obj_ptr = Z_OBJ(closure->this_ptr);
|
||||
}
|
||||
*ce_ptr = Z_OBJCE(closure->this_ptr);
|
||||
} else {
|
||||
if (obj_ptr) {
|
||||
} else {
|
||||
*obj_ptr = NULL;
|
||||
}
|
||||
*ce_ptr = closure->func.common.scope;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
@ -457,7 +462,7 @@ void zend_register_closure_ce(void) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zval *this_ptr) /* {{{ */
|
||||
ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr) /* {{{ */
|
||||
{
|
||||
zend_closure *closure;
|
||||
|
||||
@ -512,6 +517,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
|
||||
* If the closure is unscoped, it has no bound object.
|
||||
* The the closure is scoped, it's either static or it's bound */
|
||||
closure->func.common.scope = scope;
|
||||
closure->called_scope = called_scope;
|
||||
if (scope) {
|
||||
closure->func.common.fn_flags |= ZEND_ACC_PUBLIC;
|
||||
if (this_ptr && Z_TYPE_P(this_ptr) == IS_OBJECT && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0) {
|
||||
|
@ -28,7 +28,7 @@ void zend_register_closure_ce(void);
|
||||
|
||||
extern ZEND_API zend_class_entry *zend_ce_closure;
|
||||
|
||||
ZEND_API void zend_create_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zval *this_ptr);
|
||||
ZEND_API void zend_create_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr);
|
||||
ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *obj);
|
||||
ZEND_API const zend_function *zend_get_closure_method_def(zval *obj);
|
||||
ZEND_API zval* zend_get_closure_this_ptr(zval *obj);
|
||||
|
@ -7301,9 +7301,11 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
|
||||
|
||||
if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) ||
|
||||
(EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
|
||||
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc), EX(called_scope), NULL);
|
||||
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
|
||||
EG(scope), EX(called_scope), NULL);
|
||||
} else {
|
||||
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc), EG(scope), Z_OBJ(EX(This)) ? &EX(This) : NULL);
|
||||
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
|
||||
EG(scope), EX(called_scope), Z_OBJ(EX(This)) ? &EX(This) : NULL);
|
||||
}
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
|
@ -7990,9 +7990,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_C
|
||||
|
||||
if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) ||
|
||||
(EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
|
||||
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc), EX(called_scope), NULL);
|
||||
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
|
||||
EG(scope), EX(called_scope), NULL);
|
||||
} else {
|
||||
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc), EG(scope), Z_OBJ(EX(This)) ? &EX(This) : NULL);
|
||||
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
|
||||
EG(scope), EX(called_scope), Z_OBJ(EX(This)) ? &EX(This) : NULL);
|
||||
}
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
|
Loading…
Reference in New Issue
Block a user