And promote it to be fatal.
--FILE--
<?php
-Interface InvokeAble {
- static function __invoke();
-}
-
class Bar {
private function __invoke() {
return __CLASS__;
?>
--EXPECTF--
-Warning: The magic method InvokeAble::__invoke() cannot be static in %sbug61025.php on line %d
-
Warning: The magic method Bar::__invoke() must have public visibility in %sbug61025.php on line %d
Bar
Fatal error: Uncaught Error: Call to private method Bar::__invoke() from global scope in %s:%d
?>
--EXPECTF--
-Warning: The magic method A::__invoke() cannot be static in %s on line %d
-A
+Fatal error: Method A::__invoke() cannot be static in %s on line %d
echo "Done\n";
?>
--EXPECTF--
-Fatal error: Constructor test::__construct() cannot be static in %s on line %d
+Fatal error: Method test::__construct() cannot be static in %s on line %d
echo "Done\n";
?>
--EXPECTF--
-Fatal error: Destructor test::__destruct() cannot be static in %s on line %d
+Fatal error: Method test::__destruct() cannot be static in %s on line %d
echo "Done\n";
?>
--EXPECTF--
-Fatal error: Clone method test::__clone() cannot be static in %s on line %d
+Fatal error: Method test::__clone() cannot be static in %s on line %d
?>
--EXPECTF--
-Warning: The magic method foo::__unset() cannot be static in %s on line %d
+Fatal error: Method foo::__unset() cannot be static in %s on line %d
?>
--EXPECTF--
-Warning: The magic method a::__call() cannot be static in %s on line %d
+Fatal error: Method a::__call() cannot be static in %s on line %d
?>
--EXPECTF--
-Warning: The magic method a::__callStatic() must be static in %s on line %d
+Fatal error: Method a::__callStatic() must be static in %s on line %d
--EXPECTF--
Warning: The magic method a::__toString() must have public visibility in %s on line %d
-Warning: The magic method a::__toString() cannot be static in %s on line %d
-
Fatal error: Method a::__toString() cannot take arguments in %s on line %d
}
?>
--EXPECTF--
-Warning: The magic method Foo::__serialize() cannot be static in %s on line %d
-
Fatal error: Method Foo::__serialize() cannot take arguments in %s on line %d
?>
--EXPECTF--
-Warning: The magic method Foo::__set_state() must be static in %s on line %d
+Fatal error: Method Foo::__set_state() must be static in %s on line %d
}
?>
--EXPECTF--
-Warning: The magic method Foo::__unserialize() cannot be static in %s on line %d
-
Fatal error: Method Foo::__unserialize() must take exactly 1 argument in %s on line %d
}
}
+static void zend_check_magic_method_non_static(
+ const char *name, const zend_class_entry *ce, const zend_function *fptr, int error_type)
+{
+ if (fptr->common.fn_flags & ZEND_ACC_STATIC) {
+ zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(ce->name), name);
+ }
+}
+
+static void zend_check_magic_method_static(
+ const char *name, const zend_class_entry *ce, const zend_function *fptr, int error_type)
+{
+ if (!(fptr->common.fn_flags & ZEND_ACC_STATIC)) {
+ zend_error(error_type, "Method %s::%s() must be static", ZSTR_VAL(ce->name), name);
+ }
+}
+
ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, zend_string *lcname, int error_type) /* {{{ */
{
if (ZSTR_VAL(fptr->common.function_name)[0] != '_'
return;
}
- if (zend_string_equals_literal(lcname, ZEND_DESTRUCTOR_FUNC_NAME)) {
+ if (zend_string_equals_literal(lcname, ZEND_CONSTRUCTOR_FUNC_NAME)) {
+ zend_check_magic_method_non_static("__construct", ce, fptr, error_type);
+ } else if (zend_string_equals_literal(lcname, ZEND_DESTRUCTOR_FUNC_NAME)) {
zend_check_magic_method_args(0, "__destruct", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__destruct", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, ZEND_CLONE_FUNC_NAME)) {
zend_check_magic_method_args(0, "__clone", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__clone", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, ZEND_GET_FUNC_NAME)) {
zend_check_magic_method_args(1, "__get", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__get", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, ZEND_SET_FUNC_NAME)) {
zend_check_magic_method_args(2, "__set", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__set", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, ZEND_UNSET_FUNC_NAME)) {
zend_check_magic_method_args(1, "__unset", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__unset", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, ZEND_ISSET_FUNC_NAME)) {
zend_check_magic_method_args(1, "__isset", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__isset", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) {
zend_check_magic_method_args(2, "__call", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__call", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) {
zend_check_magic_method_args(2, "__callStatic", ce, fptr, error_type);
+ zend_check_magic_method_static("__callStatic", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) {
zend_check_magic_method_args(0, "__toString", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__toString", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) {
zend_check_magic_method_args(0, "__debugInfo", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__debugInfo", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, "__serialize")) {
zend_check_magic_method_args(0, "__serialize", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__serialize", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, "__unserialize")) {
zend_check_magic_method_args(1, "__unserialize", ce, fptr, error_type);
+ zend_check_magic_method_non_static("__unserialize", ce, fptr, error_type);
} else if (zend_string_equals_literal(lcname, "__set_state")) {
zend_check_magic_method_args(1, "__set_state", ce, fptr, error_type);
+ zend_check_magic_method_static("__set_state", ce, fptr, error_type);
+ } else if (zend_string_equals_literal(lcname, "__invoke")) {
+ zend_check_magic_method_non_static("__invoke", ce, fptr, error_type);
}
}
/* }}} */
}
if (reg_function) {
zend_check_magic_method_implementation(
- scope, reg_function, lowercase_name, error_type);
+ scope, reg_function, lowercase_name, E_CORE_ERROR);
}
}
ptr++;
scope->__unserialize = __unserialize;
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));
- }
- }
- if (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));
- }
- }
- if (clone) {
- if (clone->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error(error_type, "%s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(clone->common.function_name));
- }
- }
- if (__call) {
- if (__call->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__call->common.function_name));
- }
}
- if (__callstatic) {
- if (!(__callstatic->common.fn_flags & ZEND_ACC_STATIC)) {
- zend_error(error_type, "Method %s::%s() must be static", ZSTR_VAL(scope->name), ZSTR_VAL(__callstatic->common.function_name));
- }
- __callstatic->common.fn_flags |= ZEND_ACC_STATIC;
- }
- if (__tostring) {
- if (__tostring->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__tostring->common.function_name));
- }
- }
- if (__get) {
- if (__get->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__get->common.function_name));
- }
- }
- if (__set) {
- if (__set->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__set->common.function_name));
- }
- }
- if (__unset) {
- if (__unset->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__unset->common.function_name));
- }
- }
- if (__isset) {
- if (__isset->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__isset->common.function_name));
- }
- }
- if (__debugInfo) {
- if (__debugInfo->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error(error_type, "Method %s::%s() cannot be static", ZSTR_VAL(scope->name), ZSTR_VAL(__debugInfo->common.function_name));
- }
- }
-
if (ctor && (ctor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
zend_error_noreturn(E_CORE_ERROR, "Constructor %s::%s() cannot declare a return type", ZSTR_VAL(scope->name), ZSTR_VAL(ctor->common.function_name));
}
ZEND_HASH_FOREACH_END();
}
-static void zend_check_magic_method_attr(uint32_t attr, zend_class_entry *ce, const char* method, zend_bool is_static) /* {{{ */
+static void zend_check_magic_method_attr(uint32_t attr, zend_class_entry *ce, const char* method) /* {{{ */
{
if (!(attr & ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING,
"The magic method %s::%s() must have public visibility",
ZSTR_VAL(ce->name), method);
}
-
- if (is_static) {
- if (!(attr & ZEND_ACC_STATIC)) {
- zend_error(E_WARNING,
- "The magic method %s::%s() must be static",
- ZSTR_VAL(ce->name), method);
- }
- } else if (attr & ZEND_ACC_STATIC) {
- zend_error(E_WARNING,
- "The magic method %s::%s() cannot be static",
- ZSTR_VAL(ce->name), method);
- }
}
/* }}} */
} else if (zend_string_equals_literal(lcname, ZEND_CLONE_FUNC_NAME)) {
ce->clone = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) {
- zend_check_magic_method_attr(fn_flags, ce, "__call", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__call");
ce->__call = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) {
- zend_check_magic_method_attr(fn_flags, ce, "__callStatic", 1);
+ zend_check_magic_method_attr(fn_flags, ce, "__callStatic");
ce->__callstatic = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_GET_FUNC_NAME)) {
- zend_check_magic_method_attr(fn_flags, ce, "__get", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__get");
ce->__get = (zend_function *) op_array;
ce->ce_flags |= ZEND_ACC_USE_GUARDS;
} else if (zend_string_equals_literal(lcname, ZEND_SET_FUNC_NAME)) {
- zend_check_magic_method_attr(fn_flags, ce, "__set", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__set");
ce->__set = (zend_function *) op_array;
ce->ce_flags |= ZEND_ACC_USE_GUARDS;
} else if (zend_string_equals_literal(lcname, ZEND_UNSET_FUNC_NAME)) {
- zend_check_magic_method_attr(fn_flags, ce, "__unset", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__unset");
ce->__unset = (zend_function *) op_array;
ce->ce_flags |= ZEND_ACC_USE_GUARDS;
} else if (zend_string_equals_literal(lcname, ZEND_ISSET_FUNC_NAME)) {
- zend_check_magic_method_attr(fn_flags, ce, "__isset", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__isset");
ce->__isset = (zend_function *) op_array;
ce->ce_flags |= ZEND_ACC_USE_GUARDS;
} else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) {
- zend_check_magic_method_attr(fn_flags, ce, "__toString", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__toString");
ce->__tostring = (zend_function *) op_array;
add_stringable_interface(ce);
} else if (zend_string_equals_literal(lcname, ZEND_INVOKE_FUNC_NAME)) {
- zend_check_magic_method_attr(fn_flags, ce, "__invoke", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__invoke");
} else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) {
- zend_check_magic_method_attr(fn_flags, ce, "__debugInfo", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__debugInfo");
ce->__debugInfo = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, "__serialize")) {
- zend_check_magic_method_attr(fn_flags, ce, "__serialize", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__serialize");
ce->__serialize = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, "__unserialize")) {
- zend_check_magic_method_attr(fn_flags, ce, "__unserialize", 0);
+ zend_check_magic_method_attr(fn_flags, ce, "__unserialize");
ce->__unserialize = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, "__set_state")) {
- zend_check_magic_method_attr(fn_flags, ce, "__set_state", 1);
+ zend_check_magic_method_attr(fn_flags, ce, "__set_state");
}
return lcname;
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));
- }
if (ce->constructor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_error_noreturn(E_COMPILE_ERROR,
"Constructor %s::%s() cannot declare a return type",
}
}
if (ce->destructor) {
- 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));
- } else if (ce->destructor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ if (ce->destructor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_error_noreturn(E_COMPILE_ERROR,
"Destructor %s::%s() cannot declare a return type",
ZSTR_VAL(ce->name), ZSTR_VAL(ce->destructor->common.function_name));
}
}
if (ce->clone) {
- if (ce->clone->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error_noreturn(E_COMPILE_ERROR, "Clone method %s::%s() cannot be static",
- ZSTR_VAL(ce->name), ZSTR_VAL(ce->clone->common.function_name));
- } else if (ce->clone->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ if (ce->clone->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_error_noreturn(E_COMPILE_ERROR,
"Clone method %s::%s() cannot declare a return type",
ZSTR_VAL(ce->name), ZSTR_VAL(ce->clone->common.function_name));
+++ /dev/null
---TEST--
-Ensure exceptions are handled properly when thrown in a statically declared __call.
---FILE--
-<?php
-class A {
- static function __call($strMethod, $arrArgs) {
- @var_dump($this);
- throw new Exception;
- echo "You should not see this";
- }
- function test() {
- A::unknownCalledWithSRO(1,2,3);
- }
-}
-
-class B extends A {
- function test() {
- B::unknownCalledWithSROFromChild(1,2,3);
- }
-}
-
-$a = new A();
-
-echo "---> Invoke __call via simple method call.\n";
-try {
- $a->unknown();
-} catch (Exception $e) {
- echo "Exception caught OK; continuing.\n";
-}
-
-echo "\n\n---> Invoke __call via scope resolution operator within instance.\n";
-try {
- $a->test();
-} catch (Exception $e) {
- echo "Exception caught OK; continuing.\n";
-}
-
-echo "\n\n---> Invoke __call via scope resolution operator within child instance.\n";
-$b = new B();
-try {
- $b->test();
-} catch (Exception $e) {
- echo "Exception caught OK; continuing.\n";
-}
-
-echo "\n\n---> Invoke __call via callback.\n";
-try {
- call_user_func(array($b, 'unknownCallback'), 1,2,3);
-} catch (Exception $e) {
- echo "Exception caught OK; continuing.\n";
-}
-?>
---EXPECTF--
-Warning: The magic method A::__call() cannot be static in %s on line 3
----> Invoke __call via simple method call.
-object(A)#1 (0) {
-}
-Exception caught OK; continuing.
-
-
----> Invoke __call via scope resolution operator within instance.
-object(A)#1 (0) {
-}
-Exception caught OK; continuing.
-
-
----> Invoke __call via scope resolution operator within child instance.
-object(B)#2 (0) {
-}
-Exception caught OK; continuing.
-
-
----> Invoke __call via callback.
-object(B)#2 (0) {
-}
-Exception caught OK; continuing.