summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-02-12 17:34:55 +0100
committerNikita Popov <nikita.ppv@gmail.com>2019-02-12 17:36:07 +0100
commit93641539429c41a8997016ee4a4502882b0a722e (patch)
treecd2fe010e72d7b256eebaabf6afb0e371b89ace9
parentd77ad27415a34e4f5908cb262567b7b6f0eca17f (diff)
downloadphp-git-93641539429c41a8997016ee4a4502882b0a722e.tar.gz
Fixed bug #76430
It's somewhat ambiguous what exactly the correct behavior is supposed to be, I'm just picking something more or less reasonable here.
-rw-r--r--NEWS3
-rw-r--r--Zend/tests/bug76430.phpt22
-rw-r--r--Zend/tests/nested_method_and_function.phpt2
-rw-r--r--Zend/zend_compile.c28
4 files changed, 45 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index 2a76ca3c2a..65997b02d8 100644
--- a/NEWS
+++ b/NEWS
@@ -5,7 +5,8 @@ PHP NEWS
- Core:
. Implemented request #76148 (Add array_key_exists() to the list of
specially compiled functions). (Majkl578)
- . Fixed bug #77546 (iptcembed broken function). (gdegoulet)
+ . Fixed bug #76430 (__METHOD__ inconsistent outside of method).
+ (Ryan McCullagh, Nikita)
- CURL:
. Fixed bug #76480 (Use curl_multi_wait() so that timeouts are respected).
diff --git a/Zend/tests/bug76430.phpt b/Zend/tests/bug76430.phpt
new file mode 100644
index 0000000000..f122d00984
--- /dev/null
+++ b/Zend/tests/bug76430.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #76430: __METHOD__ inconsistent outside of method
+--FILE--
+<?php
+
+class Foo {
+ const X = __METHOD__;
+}
+function foo() {
+ class Bar {
+ const X = __METHOD__;
+ }
+}
+
+foo();
+var_dump(Foo::X);
+var_dump(Bar::X);
+
+?>
+--EXPECT--
+string(0) ""
+string(0) ""
diff --git a/Zend/tests/nested_method_and_function.phpt b/Zend/tests/nested_method_and_function.phpt
index c63c601eaf..3d19a06088 100644
--- a/Zend/tests/nested_method_and_function.phpt
+++ b/Zend/tests/nested_method_and_function.phpt
@@ -30,7 +30,7 @@ $c();
--EXPECT--
string(7) "Baz\foo"
string(7) "Baz\foo"
-string(7) "Baz\Foo"
+string(0) ""
string(3) "bar"
string(12) "Baz\Foo::bar"
string(7) "Baz\Foo"
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index cb7b30c265..cb961be234 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -5784,6 +5784,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
zend_ast *return_type_ast = decl->child[3];
zend_bool is_method = decl->kind == ZEND_AST_METHOD;
+ zend_class_entry *orig_class_entry = CG(active_class_entry);
zend_op_array *orig_op_array = CG(active_op_array);
zend_op_array *op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
zend_oparray_context orig_oparray_context;
@@ -5816,6 +5817,13 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
CG(active_op_array) = op_array;
+ /* Do not leak the class scope into free standing functions, even if they are dynamically
+ * defined inside a class method. This is necessary for correct handling of magic constants.
+ * For example __CLASS__ should always be "" inside a free standing function. */
+ if (decl->kind == ZEND_AST_FUNC_DECL) {
+ CG(active_class_entry) = NULL;
+ }
+
if (toplevel) {
op_array->fn_flags |= ZEND_ACC_TOP_LEVEL;
}
@@ -5863,6 +5871,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
zend_stack_del_top(&CG(loop_var_stack));
CG(active_op_array) = orig_op_array;
+ CG(active_class_entry) = orig_class_entry;
}
/* }}} */
@@ -6724,17 +6733,20 @@ static zend_bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast) /* {{{ */
}
break;
case T_METHOD_C:
- if ((op_array && !op_array->scope && op_array->function_name) || (op_array->fn_flags & ZEND_ACC_CLOSURE)) {
- ZVAL_STR_COPY(zv, op_array->function_name);
- } else if (ce) {
- if (op_array && op_array->function_name) {
- ZVAL_NEW_STR(zv, zend_concat3(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), "::", 2,
+ /* Detect whether we are directly inside a class (e.g. a class constant) and treat
+ * this as not being inside a function. */
+ if (op_array && ce && !op_array->scope && !(op_array->fn_flags & ZEND_ACC_CLOSURE)) {
+ op_array = NULL;
+ }
+ if (op_array && op_array->function_name) {
+ if (op_array->scope) {
+ ZVAL_NEW_STR(zv, zend_concat3(
+ ZSTR_VAL(op_array->scope->name), ZSTR_LEN(op_array->scope->name),
+ "::", 2,
ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name)));
} else {
- ZVAL_STR_COPY(zv, ce->name);
+ ZVAL_STR_COPY(zv, op_array->function_name);
}
- } else if (op_array && op_array->function_name) {
- ZVAL_STR_COPY(zv, op_array->function_name);
} else {
ZVAL_EMPTY_STRING(zv);
}