mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Improve error message class type
Refer to interfaces/enums instead of classes in more places. Closes GH-7792 Closes GH-8187
This commit is contained in:
parent
b9b134de5c
commit
733023b2e3
1
NEWS
1
NEWS
@ -8,6 +8,7 @@ PHP NEWS
|
||||
- Core:
|
||||
. Fixed bug #81380 (Observer may not be initialized properly). (krakjoe)
|
||||
. Fixed bug GH-7771 (Fix filename/lineno of constant expressions). (ilutov)
|
||||
. Fixed bug GH-7792 (Improve class type in error messages). (ilutov)
|
||||
|
||||
- Intl:
|
||||
. Update all grandfathered language tags with preferred values
|
||||
|
@ -11,4 +11,4 @@ interface c extends a, b { }
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class c cannot implement previously implemented interface a in %s on line %d
|
||||
Fatal error: Interface c cannot implement previously implemented interface a in %s on line %d
|
||||
|
@ -19,4 +19,4 @@ interface I3 extends I1, I2
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class I3 inherits both I1::C and I2::C, which is ambiguous in %s on line %d
|
||||
Fatal error: Interface I3 inherits both I1::C and I2::C, which is ambiguous in %s on line %d
|
||||
|
@ -7,4 +7,4 @@ enum Foo: int implements BackedEnum {}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class Foo cannot implement previously implemented interface BackedEnum in %s on line %d
|
||||
Fatal error: Enum Foo cannot implement previously implemented interface BackedEnum in %s on line %d
|
||||
|
@ -7,4 +7,4 @@ enum Foo implements UnitEnum {}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class Foo cannot implement previously implemented interface UnitEnum in %s on line %d
|
||||
Fatal error: Enum Foo cannot implement previously implemented interface UnitEnum in %s on line %d
|
||||
|
14
Zend/tests/gh7792_1.phpt
Normal file
14
Zend/tests/gh7792_1.phpt
Normal file
@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
GH-7792 (Refer to enum as enum instead of class)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
interface A {
|
||||
public function a(): void;
|
||||
}
|
||||
|
||||
enum B implements A {}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Enum B must implement 1 abstract private method (A::a) in %s on line %d
|
10
Zend/tests/gh7792_2.phpt
Normal file
10
Zend/tests/gh7792_2.phpt
Normal file
@ -0,0 +1,10 @@
|
||||
--TEST--
|
||||
GH-7792 (Refer to enum as enum instead of class)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
enum Foo implements Throwable {}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Enum Foo cannot implement interface Throwable in %s on line %d
|
18
Zend/tests/gh7792_3.phpt
Normal file
18
Zend/tests/gh7792_3.phpt
Normal file
@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
GH-7792 (Refer to enum as enum instead of class)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
interface A {
|
||||
const FOO = 'foo';
|
||||
}
|
||||
|
||||
interface B {
|
||||
const FOO = 'foo';
|
||||
}
|
||||
|
||||
enum Foo implements A, B {}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Enum Foo inherits both A::FOO and B::FOO, which is ambiguous in %s on line %d
|
12
Zend/tests/gh7792_4.phpt
Normal file
12
Zend/tests/gh7792_4.phpt
Normal file
@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
GH-7792 (Refer to enum as enum instead of class)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
interface A {}
|
||||
|
||||
enum Foo implements A, A {}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Enum Foo cannot implement previously implemented interface A in %s on line %d
|
10
Zend/tests/gh7792_5.phpt
Normal file
10
Zend/tests/gh7792_5.phpt
Normal file
@ -0,0 +1,10 @@
|
||||
--TEST--
|
||||
GH-7792 (Refer to enum as enum instead of class)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
enum Foo implements Traversable {}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Fatal error: Enum Foo must implement interface Traversable as part of either Iterator or IteratorAggregate in Unknown on line 0
|
@ -12,4 +12,4 @@ interface bar extends foo, foo {
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class bar cannot implement previously implemented interface foo in %s on line %d
|
||||
Fatal error: Interface bar cannot implement previously implemented interface foo in %s on line %d
|
||||
|
@ -4783,14 +4783,16 @@ ZEND_API void zend_restore_error_handling(zend_error_handling *saved) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API ZEND_COLD const char *zend_get_object_type(const zend_class_entry *ce) /* {{{ */
|
||||
ZEND_API ZEND_COLD const char *zend_get_object_type_case(const zend_class_entry *ce, bool upper_case) /* {{{ */
|
||||
{
|
||||
if(ce->ce_flags & ZEND_ACC_TRAIT) {
|
||||
return "trait";
|
||||
if (ce->ce_flags & ZEND_ACC_TRAIT) {
|
||||
return upper_case ? "Trait" : "trait";
|
||||
} else if (ce->ce_flags & ZEND_ACC_INTERFACE) {
|
||||
return "interface";
|
||||
return upper_case ? "Interface" : "interface";
|
||||
} else if (ce->ce_flags & ZEND_ACC_ENUM) {
|
||||
return upper_case ? "Enum" : "enum";
|
||||
} else {
|
||||
return "class";
|
||||
return upper_case ? "Class" : "class";
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -721,7 +721,17 @@ static zend_always_inline zend_result zend_forbid_dynamic_call(void)
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_API ZEND_COLD const char *zend_get_object_type(const zend_class_entry *ce);
|
||||
ZEND_API ZEND_COLD const char *zend_get_object_type_case(const zend_class_entry *ce, bool upper_case);
|
||||
|
||||
static zend_always_inline const char *zend_get_object_type(const zend_class_entry *ce)
|
||||
{
|
||||
return zend_get_object_type_case(ce, false);
|
||||
}
|
||||
|
||||
static zend_always_inline const char *zend_get_object_type_uc(const zend_class_entry *ce)
|
||||
{
|
||||
return zend_get_object_type_case(ce, true);
|
||||
}
|
||||
|
||||
ZEND_API bool zend_is_iterable(zval *iterable);
|
||||
|
||||
|
@ -67,8 +67,13 @@ static int zend_implement_throwable(zend_class_entry *interface, zend_class_entr
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
bool can_extend = (class_type->ce_flags & ZEND_ACC_ENUM) == 0;
|
||||
|
||||
zend_error_noreturn(E_ERROR,
|
||||
"Class %s cannot implement interface %s, extend Exception or Error instead",
|
||||
can_extend
|
||||
? "%s %s cannot implement interface %s, extend Exception or Error instead"
|
||||
: "%s %s cannot implement interface %s",
|
||||
zend_get_object_type_uc(class_type),
|
||||
ZSTR_VAL(class_type->name),
|
||||
ZSTR_VAL(interface->name));
|
||||
return FAILURE;
|
||||
|
@ -1285,7 +1285,7 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke
|
||||
static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
|
||||
{
|
||||
if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
|
||||
zend_error_noreturn(E_CORE_ERROR, "Class %s could not implement interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
|
||||
zend_error_noreturn(E_CORE_ERROR, "%s %s could not implement interface %s", zend_get_object_type_uc(ce), ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
|
||||
}
|
||||
/* This should be prevented by the class lookup logic. */
|
||||
ZEND_ASSERT(ce != iface);
|
||||
@ -1610,7 +1610,8 @@ static bool do_inherit_constant_check(
|
||||
|
||||
if (old_constant->ce != parent_constant->ce && old_constant->ce != ce) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"Class %s inherits both %s::%s and %s::%s, which is ambiguous",
|
||||
"%s %s inherits both %s::%s and %s::%s, which is ambiguous",
|
||||
zend_get_object_type_uc(ce),
|
||||
ZSTR_VAL(ce->name),
|
||||
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
|
||||
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
|
||||
@ -1729,7 +1730,10 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry
|
||||
if (interfaces[j] == iface) {
|
||||
if (j >= num_parent_interfaces) {
|
||||
efree(interfaces);
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "%s %s cannot implement previously implemented interface %s",
|
||||
zend_get_object_type_uc(ce),
|
||||
ZSTR_VAL(ce->name),
|
||||
ZSTR_VAL(iface->name));
|
||||
return;
|
||||
}
|
||||
/* skip duplications */
|
||||
@ -2311,6 +2315,7 @@ void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
|
||||
zend_function *func;
|
||||
zend_abstract_info ai;
|
||||
bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
|
||||
bool can_be_abstract = (ce->ce_flags & ZEND_ACC_ENUM) == 0;
|
||||
memset(&ai, 0, sizeof(ai));
|
||||
|
||||
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, func) {
|
||||
@ -2324,9 +2329,10 @@ void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
if (ai.cnt) {
|
||||
zend_error_noreturn(E_ERROR, !is_explicit_abstract
|
||||
? "Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")"
|
||||
: "Class %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
|
||||
zend_error_noreturn(E_ERROR, !is_explicit_abstract && can_be_abstract
|
||||
? "%s %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")"
|
||||
: "%s %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
|
||||
zend_get_object_type_uc(ce),
|
||||
ZSTR_VAL(ce->name), ai.cnt,
|
||||
ai.cnt > 1 ? "s" : "",
|
||||
DISPLAY_ABSTRACT_FN(0),
|
||||
|
@ -266,7 +266,8 @@ static int zend_implement_traversable(zend_class_entry *interface, zend_class_en
|
||||
}
|
||||
}
|
||||
}
|
||||
zend_error_noreturn(E_CORE_ERROR, "Class %s must implement interface %s as part of either %s or %s",
|
||||
zend_error_noreturn(E_CORE_ERROR, "%s %s must implement interface %s as part of either %s or %s",
|
||||
zend_get_object_type_uc(class_type),
|
||||
ZSTR_VAL(class_type->name),
|
||||
ZSTR_VAL(zend_ce_traversable->name),
|
||||
ZSTR_VAL(zend_ce_iterator->name),
|
||||
|
Loading…
Reference in New Issue
Block a user