summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--UPGRADING.INTERNALS3
-rw-r--r--Zend/tests/bug77613.phpt19
-rw-r--r--Zend/zend_API.c2
-rw-r--r--Zend/zend_builtin_functions.c2
-rw-r--r--Zend/zend_compile.c2
-rw-r--r--Zend/zend_compile.h6
-rw-r--r--Zend/zend_inheritance.c9
-rw-r--r--ext/reflection/php_reflection.c10
8 files changed, 40 insertions, 13 deletions
diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index e4147f249c..e190b291e9 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -38,9 +38,6 @@ PHP 7.4 INTERNALS UPGRADE NOTES
instead of zval*.
c. Function/property/class flags changes
- - ZEND_ACC_CTOR and ZEND_ACC_DTOR are removed. It's possible to check if
- method is a constructor/destructor using the following condition
- (func->common.scope->constructor == func).
- ZEND_ACC_IMPLEMENTED_ABSTRACT is removed (it was used only internally
during inheritance).
- ZEND_ACC_IMPLICIT_PUBLIC is removed (it was used only for reflection)
diff --git a/Zend/tests/bug77613.phpt b/Zend/tests/bug77613.phpt
new file mode 100644
index 0000000000..02d7ad4b72
--- /dev/null
+++ b/Zend/tests/bug77613.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #77613 (method visibility change)
+--FILE--
+<?php
+class A {
+ public function __construct() {
+ static $foo;
+ }
+}
+
+class B extends A { }
+
+class C extends B {
+ private function __construct() {}
+}
+?>
+OK
+--EXPECT--
+OK
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 60f0e29931..f191ca25b9 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -2340,12 +2340,14 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
scope->__isset = __isset;
scope->__debugInfo = __debugInfo;
if (ctor) {
+ ctor->common.fn_flags |= ZEND_ACC_CTOR;
if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
zend_error(error_type, "Constructor %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(ctor->common.function_name));
}
ctor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
}
if (dtor) {
+ dtor->common.fn_flags |= ZEND_ACC_DTOR;
if (dtor->common.fn_flags & ZEND_ACC_STATIC) {
zend_error(error_type, "Destructor %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(dtor->common.function_name));
}
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index ab365967bd..93bbd3bc87 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -1291,7 +1291,7 @@ ZEND_FUNCTION(get_class_methods)
if (!key) {
ZVAL_STR_COPY(&method_name, mptr->common.function_name);
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &method_name);
- } else if (mptr->common.scope->constructor != mptr ||
+ } else if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 ||
mptr->common.scope == ce ||
zend_binary_strcasecmp(ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(mptr->common.function_name), len) == 0) {
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index cb961be234..03f8cf2563 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -6270,6 +6270,7 @@ void zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
}
if (ce->constructor) {
+ ce->constructor->common.fn_flags |= ZEND_ACC_CTOR;
if (ce->constructor->common.fn_flags & ZEND_ACC_STATIC) {
zend_error_noreturn(E_COMPILE_ERROR, "Constructor %s::%s() cannot be static",
ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
@@ -6281,6 +6282,7 @@ void zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
}
}
if (ce->destructor) {
+ ce->destructor->common.fn_flags |= ZEND_ACC_DTOR;
if (ce->destructor->common.fn_flags & ZEND_ACC_STATIC) {
zend_error_noreturn(E_COMPILE_ERROR, "Destructor %s::%s() cannot be static",
ZSTR_VAL(ce->name), ZSTR_VAL(ce->destructor->common.function_name));
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 84d6b9f7b3..d12199a6d6 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -316,6 +316,12 @@ typedef struct _zend_oparray_context {
/* op_array is preloaded | | | */
#define ZEND_ACC_PRELOADED (1 << 27) /* | X | | */
/* | | | */
+/* functions is a constructor | | | */
+#define ZEND_ACC_CTOR (1 << 28) /* | X | | */
+/* | | | */
+/* function is a destructor | | | */
+#define ZEND_ACC_DTOR (1 << 29) /* | X | | */
+/* | | | */
/* op_array uses strict mode types | | | */
#define ZEND_ACC_STRICT_TYPES (1 << 31) /* | X | | */
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c
index 6a66846145..858a36213c 100644
--- a/Zend/zend_inheritance.c
+++ b/Zend/zend_inheritance.c
@@ -272,7 +272,7 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
/* Checks for constructors only if they are declared in an interface,
* or explicitly marked as abstract
*/
- if ((fe->common.scope->constructor == fe)
+ if ((fe->common.fn_flags & ZEND_ACC_CTOR)
&& ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
&& (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
return 1;
@@ -574,7 +574,7 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
zend_function *proto = parent->common.prototype ?
parent->common.prototype : parent;
- if (parent->common.scope->constructor != parent) {
+ if (!(parent_flags & ZEND_ACC_CTOR)) {
if (!proto) {
proto = parent;
}
@@ -1322,10 +1322,11 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen
zend_string *lowercase_name = zend_string_tolower(ce->name);
lowercase_name = zend_new_interned_string(lowercase_name);
if (!memcmp(ZSTR_VAL(mname), ZSTR_VAL(lowercase_name), ZSTR_LEN(mname))) {
- if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) {
+ if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) {
zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ZSTR_VAL(ce->name));
}
ce->constructor = fe;
+ fe->common.fn_flags |= ZEND_ACC_CTOR;
}
zend_string_release_ex(lowercase_name, 0);
}
@@ -1986,7 +1987,7 @@ static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract
if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
ai->afn[ai->cnt] = fn;
}
- if (fn->common.scope->constructor == fn) {
+ if (fn->common.fn_flags & ZEND_ACC_CTOR) {
if (!ai->ctor) {
ai->cnt++;
ai->ctor = 1;
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 1e11b8735a..8bfafe7c5a 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -485,7 +485,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char
size_t len = ZSTR_LEN(mptr->common.function_name);
/* Do not display old-style inherited constructors */
- if (mptr->common.scope->constructor != mptr
+ if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0
|| mptr->common.scope == ce
|| !key
|| zend_binary_strcasecmp(ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(mptr->common.function_name), len) == 0)
@@ -756,10 +756,10 @@ static void _function_string(smart_str *str, zend_function *fptr, zend_class_ent
if (fptr->common.prototype && fptr->common.prototype->common.scope) {
smart_str_append_printf(str, ", prototype %s", ZSTR_VAL(fptr->common.prototype->common.scope->name));
}
- if (fptr->common.scope && fptr->common.scope->constructor == fptr) {
+ if (fptr->common.fn_flags & ZEND_ACC_CTOR) {
smart_str_appends(str, ", ctor");
}
- if (fptr->common.scope && fptr->common.scope->destructor == fptr) {
+ if (fptr->common.fn_flags & ZEND_ACC_DTOR) {
smart_str_appends(str, ", dtor");
}
smart_str_appends(str, "> ");
@@ -3403,7 +3403,7 @@ ZEND_METHOD(reflection_method, isConstructor)
/* we need to check if the ctor is the ctor of the class level we we
* looking at since we might be looking at an inherited old style ctor
* defined in base class. */
- RETURN_BOOL(intern->ce->constructor == mptr);
+ RETURN_BOOL(mptr->common.fn_flags & ZEND_ACC_CTOR && intern->ce->constructor && intern->ce->constructor->common.scope == mptr->common.scope);
}
/* }}} */
@@ -3418,7 +3418,7 @@ ZEND_METHOD(reflection_method, isDestructor)
return;
}
GET_REFLECTION_OBJECT_PTR(mptr);
- RETURN_BOOL(intern->ce->destructor == mptr);
+ RETURN_BOOL(mptr->common.fn_flags & ZEND_ACC_DTOR);
}
/* }}} */