summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/bug69568.phpt25
-rw-r--r--Zend/tests/parent_class_name_without_parent.phpt21
-rw-r--r--Zend/zend_closures.c34
-rw-r--r--Zend/zend_closures.h2
-rw-r--r--Zend/zend_vm_def.h6
-rw-r--r--Zend/zend_vm_execute.h6
6 files changed, 75 insertions, 19 deletions
diff --git a/Zend/tests/bug69568.phpt b/Zend/tests/bug69568.phpt
new file mode 100644
index 0000000000..18ec941d0b
--- /dev/null
+++ b/Zend/tests/bug69568.phpt
@@ -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
diff --git a/Zend/tests/parent_class_name_without_parent.phpt b/Zend/tests/parent_class_name_without_parent.phpt
new file mode 100644
index 0000000000..0e67173f87
--- /dev/null
+++ b/Zend/tests/parent_class_name_without_parent.phpt
@@ -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
+
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index 952e4ed1e0..97f0cbf57a 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -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) {
diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h
index 9862bc07cf..8d0963ec17 100644
--- a/Zend/zend_closures.h
+++ b/Zend/zend_closures.h
@@ -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);
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 089987817a..e00ee07d84 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -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();
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 3a61b5702f..85075af2a6 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -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();