Skip to content

Commit 080e02e

Browse files
committed
Improve error message class type
Refer to interfaces/enums instead of classes in more places. Closes GH-7792
1 parent e3ef7bb commit 080e02e

15 files changed

+108
-13
lines changed

Zend/tests/class_alias_009.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ interface c extends a, b { }
1111

1212
?>
1313
--EXPECTF--
14-
Fatal error: Class c cannot implement previously implemented interface a in %s on line %d
14+
Fatal error: Interface c cannot implement previously implemented interface a in %s on line %d

Zend/tests/constants/final_constants/final_const12.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ interface I3 extends I1, I2
1919

2020
?>
2121
--EXPECTF--
22-
Fatal error: Class I3 inherits both I1::C and I2::C, which is ambiguous in %s on line %d
22+
Fatal error: Interface I3 inherits both I1::C and I2::C, which is ambiguous in %s on line %d

Zend/tests/enum/no-enum-implements-backed-enum.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ enum Foo: int implements BackedEnum {}
77

88
?>
99
--EXPECTF--
10-
Fatal error: Class Foo cannot implement previously implemented interface BackedEnum in %s on line %d
10+
Fatal error: Enum Foo cannot implement previously implemented interface BackedEnum in %s on line %d

Zend/tests/enum/no-enum-implements-unit-enum.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ enum Foo implements UnitEnum {}
77

88
?>
99
--EXPECTF--
10-
Fatal error: Class Foo cannot implement previously implemented interface UnitEnum in %s on line %d
10+
Fatal error: Enum Foo cannot implement previously implemented interface UnitEnum in %s on line %d

Zend/tests/gh7792_1.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
GH-7792 (Refer to enum as enum instead of class)
3+
--FILE--
4+
<?php
5+
6+
interface A {
7+
public function a(): void;
8+
}
9+
10+
enum B implements A {}
11+
12+
?>
13+
--EXPECTF--
14+
Fatal error: Enum B must implement 1 abstract private method (A::a) in %s on line %d

Zend/tests/gh7792_2.phpt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
GH-7792 (Refer to enum as enum instead of class)
3+
--FILE--
4+
<?php
5+
6+
enum Foo implements Throwable {}
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Enum Foo cannot implement interface Throwable in %s on line %d

Zend/tests/gh7792_3.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
GH-7792 (Refer to enum as enum instead of class)
3+
--FILE--
4+
<?php
5+
6+
interface A {
7+
const FOO = 'foo';
8+
}
9+
10+
interface B {
11+
const FOO = 'foo';
12+
}
13+
14+
enum Foo implements A, B {}
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Enum Foo inherits both A::FOO and B::FOO, which is ambiguous in %s on line %d

Zend/tests/gh7792_4.phpt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
GH-7792 (Refer to enum as enum instead of class)
3+
--FILE--
4+
<?php
5+
6+
interface A {}
7+
8+
enum Foo implements A, A {}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Enum Foo cannot implement previously implemented interface A in %s on line %d

Zend/tests/gh7792_5.phpt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
GH-7792 (Refer to enum as enum instead of class)
3+
--FILE--
4+
<?php
5+
6+
enum Foo implements Traversable {}
7+
8+
?>
9+
--EXPECT--
10+
Fatal error: Enum Foo must implement interface Traversable as part of either Iterator or IteratorAggregate in Unknown on line 0

Zend/tests/objects_014.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ interface bar extends foo, foo {
1212
echo "Done\n";
1313
?>
1414
--EXPECTF--
15-
Fatal error: Class bar cannot implement previously implemented interface foo in %s on line %d
15+
Fatal error: Interface bar cannot implement previously implemented interface foo in %s on line %d

Zend/zend_API.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4789,12 +4789,28 @@ ZEND_API ZEND_COLD const char *zend_get_object_type(const zend_class_entry *ce)
47894789
return "trait";
47904790
} else if (ce->ce_flags & ZEND_ACC_INTERFACE) {
47914791
return "interface";
4792+
} else if (ce->ce_flags & ZEND_ACC_ENUM) {
4793+
return "enum";
47924794
} else {
47934795
return "class";
47944796
}
47954797
}
47964798
/* }}} */
47974799

4800+
ZEND_API ZEND_COLD const char *zend_get_object_type_uc(const zend_class_entry *ce) /* {{{ */
4801+
{
4802+
if(ce->ce_flags & ZEND_ACC_TRAIT) {
4803+
return "Trait";
4804+
} else if (ce->ce_flags & ZEND_ACC_INTERFACE) {
4805+
return "Interface";
4806+
} else if (ce->ce_flags & ZEND_ACC_ENUM) {
4807+
return "Enum";
4808+
} else {
4809+
return "Class";
4810+
}
4811+
}
4812+
/* }}} */
4813+
47984814
ZEND_API bool zend_is_iterable(zval *iterable) /* {{{ */
47994815
{
48004816
switch (Z_TYPE_P(iterable)) {

Zend/zend_API.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ static zend_always_inline zend_result zend_forbid_dynamic_call(void)
722722
}
723723

724724
ZEND_API ZEND_COLD const char *zend_get_object_type(const zend_class_entry *ce);
725+
ZEND_API ZEND_COLD const char *zend_get_object_type_uc(const zend_class_entry *ce);
725726

726727
ZEND_API bool zend_is_iterable(zval *iterable);
727728

Zend/zend_exceptions.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,13 @@ static int zend_implement_throwable(zend_class_entry *interface, zend_class_entr
6767
return SUCCESS;
6868
}
6969

70+
bool can_extend = (class_type->ce_flags & ZEND_ACC_ENUM) == 0;
71+
7072
zend_error_noreturn(E_ERROR,
71-
"Class %s cannot implement interface %s, extend Exception or Error instead",
73+
can_extend
74+
? "%s %s cannot implement interface %s, extend Exception or Error instead"
75+
: "%s %s cannot implement interface %s",
76+
zend_get_object_type_uc(class_type),
7277
ZSTR_VAL(class_type->name),
7378
ZSTR_VAL(interface->name));
7479
return FAILURE;

Zend/zend_inheritance.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
+----------------------------------------------------------------------+
1818
*/
1919

20+
#include <ctype.h>
21+
2022
#include "zend.h"
2123
#include "zend_API.h"
2224
#include "zend_compile.h"
@@ -1285,7 +1287,7 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke
12851287
static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
12861288
{
12871289
if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
1288-
zend_error_noreturn(E_CORE_ERROR, "Class %s could not implement interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1290+
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));
12891291
}
12901292
/* This should be prevented by the class lookup logic. */
12911293
ZEND_ASSERT(ce != iface);
@@ -1610,7 +1612,8 @@ static bool do_inherit_constant_check(
16101612

16111613
if (old_constant->ce != parent_constant->ce && old_constant->ce != ce) {
16121614
zend_error_noreturn(E_COMPILE_ERROR,
1613-
"Class %s inherits both %s::%s and %s::%s, which is ambiguous",
1615+
"%s %s inherits both %s::%s and %s::%s, which is ambiguous",
1616+
zend_get_object_type_uc(ce),
16141617
ZSTR_VAL(ce->name),
16151618
ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name),
16161619
ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
@@ -1729,7 +1732,10 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry
17291732
if (interfaces[j] == iface) {
17301733
if (j >= num_parent_interfaces) {
17311734
efree(interfaces);
1732-
zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1735+
zend_error_noreturn(E_COMPILE_ERROR, "%s %s cannot implement previously implemented interface %s",
1736+
zend_get_object_type_uc(ce),
1737+
ZSTR_VAL(ce->name),
1738+
ZSTR_VAL(iface->name));
17331739
return;
17341740
}
17351741
/* skip duplications */
@@ -2311,6 +2317,7 @@ void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
23112317
zend_function *func;
23122318
zend_abstract_info ai;
23132319
bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
2320+
bool can_be_abstract = (ce->ce_flags & ZEND_ACC_ENUM) == 0;
23142321
memset(&ai, 0, sizeof(ai));
23152322

23162323
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, func) {
@@ -2324,9 +2331,10 @@ void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
23242331
} ZEND_HASH_FOREACH_END();
23252332

23262333
if (ai.cnt) {
2327-
zend_error_noreturn(E_ERROR, !is_explicit_abstract
2328-
? "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 ")"
2329-
: "Class %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
2334+
zend_error_noreturn(E_ERROR, !is_explicit_abstract && can_be_abstract
2335+
? "%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 ")"
2336+
: "%s %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
2337+
zend_get_object_type_uc(ce),
23302338
ZSTR_VAL(ce->name), ai.cnt,
23312339
ai.cnt > 1 ? "s" : "",
23322340
DISPLAY_ABSTRACT_FN(0),

Zend/zend_interfaces.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ static int zend_implement_traversable(zend_class_entry *interface, zend_class_en
266266
}
267267
}
268268
}
269-
zend_error_noreturn(E_CORE_ERROR, "Class %s must implement interface %s as part of either %s or %s",
269+
zend_error_noreturn(E_CORE_ERROR, "%s %s must implement interface %s as part of either %s or %s",
270+
zend_get_object_type_uc(class_type),
270271
ZSTR_VAL(class_type->name),
271272
ZSTR_VAL(zend_ce_traversable->name),
272273
ZSTR_VAL(zend_ce_iterator->name),

0 commit comments

Comments
 (0)