mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Convert exception during inheritance to fatal error
Now that inheritance can throw deprecations again, these may be converted to exception by a custom error handler. In this case we need to convert the exception to a fatal error, as inheritance cannot safely throw in the general case.
This commit is contained in:
parent
6e477d205e
commit
100a1e8e21
5 changed files with 43 additions and 16 deletions
19
Zend/tests/deprecation_to_exception_during_inheritance.phpt
Normal file
19
Zend/tests/deprecation_to_exception_during_inheritance.phpt
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
--TEST--
|
||||||
|
Deprecation promoted to exception should result in fatal error during inheritance
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(function($code, $message) {
|
||||||
|
throw new Exception($message);
|
||||||
|
});
|
||||||
|
|
||||||
|
$class = new class extends DateTime {
|
||||||
|
public function getTimezone() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: During inheritance of DateTime: Uncaught Exception: Declaration of DateTime@anonymous::getTimezone() should be compatible with DateTime::getTimezone(): DateTimeZone|false in %s:%d
|
||||||
|
Stack trace:
|
||||||
|
#0 %s(%d): {closure}(8192, 'Declaration of ...', '%s', 8)
|
||||||
|
#1 {main} in %s on line %d
|
|
@ -968,6 +968,22 @@ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *ex, int severit
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
ZEND_NORETURN void zend_exception_uncaught_error(const char *format, ...) {
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
zend_string *prefix = zend_vstrpprintf(0, format, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
ZEND_ASSERT(EG(exception));
|
||||||
|
zval exception_zv;
|
||||||
|
ZVAL_OBJ_COPY(&exception_zv, EG(exception));
|
||||||
|
zend_clear_exception();
|
||||||
|
|
||||||
|
zend_string *exception_str = zval_get_string(&exception_zv);
|
||||||
|
zend_error_noreturn(E_ERROR,
|
||||||
|
"%s: Uncaught %s", ZSTR_VAL(prefix), ZSTR_VAL(exception_str));
|
||||||
|
}
|
||||||
|
|
||||||
ZEND_API ZEND_COLD void zend_throw_exception_object(zval *exception) /* {{{ */
|
ZEND_API ZEND_COLD void zend_throw_exception_object(zval *exception) /* {{{ */
|
||||||
{
|
{
|
||||||
if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {
|
if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {
|
||||||
|
|
|
@ -68,6 +68,7 @@ extern ZEND_API void (*zend_throw_exception_hook)(zend_object *ex);
|
||||||
|
|
||||||
/* show an exception using zend_error(severity,...), severity should be E_ERROR */
|
/* show an exception using zend_error(severity,...), severity should be E_ERROR */
|
||||||
ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *exception, int severity);
|
ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *exception, int severity);
|
||||||
|
ZEND_NORETURN void zend_exception_uncaught_error(const char *prefix, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
|
||||||
ZEND_API zend_string *zend_trace_to_string(HashTable *trace, bool include_main);
|
ZEND_API zend_string *zend_trace_to_string(HashTable *trace, bool include_main);
|
||||||
|
|
||||||
ZEND_API ZEND_COLD void zend_throw_unwind_exit(void);
|
ZEND_API ZEND_COLD void zend_throw_unwind_exit(void);
|
||||||
|
|
|
@ -1518,14 +1518,7 @@ zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string
|
||||||
}
|
}
|
||||||
if (EG(exception)) {
|
if (EG(exception)) {
|
||||||
if (!(fetch_type & ZEND_FETCH_CLASS_EXCEPTION)) {
|
if (!(fetch_type & ZEND_FETCH_CLASS_EXCEPTION)) {
|
||||||
zend_string *exception_str;
|
zend_exception_uncaught_error("During class fetch");
|
||||||
zval exception_zv;
|
|
||||||
ZVAL_OBJ(&exception_zv, EG(exception));
|
|
||||||
Z_ADDREF(exception_zv);
|
|
||||||
zend_clear_exception();
|
|
||||||
exception_str = zval_get_string(&exception_zv);
|
|
||||||
zend_error_noreturn(E_ERROR,
|
|
||||||
"During class fetch: Uncaught %s", ZSTR_VAL(exception_str));
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -877,6 +877,10 @@ static void ZEND_COLD emit_incompatible_method_error(
|
||||||
zend_error_at(E_DEPRECATED, NULL, func_lineno(child),
|
zend_error_at(E_DEPRECATED, NULL, func_lineno(child),
|
||||||
"Declaration of %s should be compatible with %s",
|
"Declaration of %s should be compatible with %s",
|
||||||
ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
|
ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
|
||||||
|
if (EG(exception)) {
|
||||||
|
zend_exception_uncaught_error(
|
||||||
|
"During inheritance of %s", ZSTR_VAL(parent_scope->name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
zend_error_at(E_COMPILE_ERROR, NULL, func_lineno(child),
|
zend_error_at(E_COMPILE_ERROR, NULL, func_lineno(child),
|
||||||
|
@ -2454,14 +2458,8 @@ static void check_unrecoverable_load_failure(zend_class_entry *ce) {
|
||||||
|| ((ce->ce_flags & ZEND_ACC_IMMUTABLE)
|
|| ((ce->ce_flags & ZEND_ACC_IMMUTABLE)
|
||||||
&& CG(unlinked_uses)
|
&& CG(unlinked_uses)
|
||||||
&& zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t)ce) == SUCCESS)) {
|
&& zend_hash_index_del(CG(unlinked_uses), (zend_long)(zend_uintptr_t)ce) == SUCCESS)) {
|
||||||
zend_string *exception_str;
|
zend_exception_uncaught_error(
|
||||||
zval exception_zv;
|
"During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
|
||||||
ZEND_ASSERT(EG(exception) && "Exception must have been thrown");
|
|
||||||
ZVAL_OBJ_COPY(&exception_zv, EG(exception));
|
|
||||||
zend_clear_exception();
|
|
||||||
exception_str = zval_get_string(&exception_zv);
|
|
||||||
zend_error_noreturn(E_ERROR,
|
|
||||||
"During inheritance of %s with variance dependencies: Uncaught %s", ZSTR_VAL(ce->name), ZSTR_VAL(exception_str));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue