From 72bd55902d1908857f47555ad69458861e1acd94 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 6 Feb 2020 11:13:13 +0100 Subject: [PATCH] Improve generated names for anonymous classes In order of preference, the generated name will be: new class extends ParentClass {}; // -> ParentClass@anonymous new class implements FirstInterface, SecondInterface {}; // -> FirstInterface@anonymous new class {}; // -> class@anonymous This is intended to display a more useful class name in error messages and stack traces, and thus make debugging easier. Closes GH-5153. --- UPGRADING | 13 +++++++- Zend/tests/anon_class_name.phpt | 30 ++++++++++++++++++ .../object_types/return_type_in_class.phpt | 4 +-- .../return_type_inheritance_in_class.phpt | 4 +-- .../return_type_inheritance_in_interface.phpt | 4 +-- Zend/tests/temporary_cleaning_013.phpt | 4 +-- .../typed_properties_065.phpt | 8 ++--- Zend/zend_compile.c | 21 +++++++++--- ext/opcache/tests/bug78937_1.phpt | 2 +- ext/opcache/tests/bug78937_2.phpt | 4 +-- ext/opcache/tests/bug78937_3.phpt | 2 +- ext/opcache/tests/bug78937_4.phpt | 2 +- ext/opcache/tests/bug78937_5.phpt | 2 +- ext/opcache/tests/bug78937_6.phpt | 2 +- .../ReflectionClass_isSubclassOf_error2.phpt | 4 +-- ext/standard/tests/class_object/bug78638.phpt | 2 +- .../get_object_vars_variation_004.phpt | Bin 741 -> 763 bytes 17 files changed, 80 insertions(+), 28 deletions(-) create mode 100644 Zend/tests/anon_class_name.phpt diff --git a/UPGRADING b/UPGRADING index 30611b1013..5174a2e52f 100644 --- a/UPGRADING +++ b/UPGRADING @@ -130,6 +130,18 @@ PHP 8.0 UPGRADE NOTES exception. . Some "Only variables should be passed by reference" notices have been converted to "Cannot pass parameter by reference" exception. + . The generated name for anonymous classes has changed. It will now include + the name of the first parent or interface: + + new class extends ParentClass {}; + // -> ParentClass@anonymous + new class implements FirstInterface, SecondInterface {}; + // -> FirstInterface@anonymous + new class {}; + // -> class@anonymous + + The name shown above is still followed by a null byte and and a unique + suffix. - COM: . Removed the ability to import case-insensitive constants from type @@ -386,7 +398,6 @@ PHP 8.0 UPGRADE NOTES writing `Foo::BAR::$baz` is now allowed. RFC: https://wiki.php.net/rfc/variable_syntax_tweaks - - Date: . Added DateTime::createFromInterface() and DateTimeImmutable::createFromInterface(). diff --git a/Zend/tests/anon_class_name.phpt b/Zend/tests/anon_class_name.phpt new file mode 100644 index 0000000000..36f613d707 --- /dev/null +++ b/Zend/tests/anon_class_name.phpt @@ -0,0 +1,30 @@ +--TEST-- +Generated names for anonymous classes +--FILE-- + +--EXPECT-- +class@anonymous +DeclaringNS\Test1@anonymous +DeclaringNS\Test1@anonymous +DeclaringNS\Test2@anonymous +DeclaringNS\Test2@anonymous diff --git a/Zend/tests/object_types/return_type_in_class.phpt b/Zend/tests/object_types/return_type_in_class.phpt index c4c1dc0516..3edb015df7 100644 --- a/Zend/tests/object_types/return_type_in_class.phpt +++ b/Zend/tests/object_types/return_type_in_class.phpt @@ -18,8 +18,8 @@ $three = new class extends Two { }; $three->a(); --EXPECTF-- -Fatal error: Uncaught TypeError: Return value of class@anonymous::a() must be an object, int returned in %s:13 +Fatal error: Uncaught TypeError: Return value of Two@anonymous::a() must be an object, int returned in %s:%d Stack trace: -#0 %s(16): class@anonymous->a() +#0 %s(%d): Two@anonymous->a() #1 {main} thrown in %s on line 13 diff --git a/Zend/tests/object_types/return_type_inheritance_in_class.phpt b/Zend/tests/object_types/return_type_inheritance_in_class.phpt index a7316136fb..23528531ec 100644 --- a/Zend/tests/object_types/return_type_inheritance_in_class.phpt +++ b/Zend/tests/object_types/return_type_inheritance_in_class.phpt @@ -18,8 +18,8 @@ $three = new class extends Two { }; $three->a(); --EXPECTF-- -Fatal error: Uncaught TypeError: Return value of class@anonymous::a() must be an object, int returned in %s:13 +Fatal error: Uncaught TypeError: Return value of Two@anonymous::a() must be an object, int returned in %s:%d Stack trace: -#0 %s(16): class@anonymous->a() +#0 %s(%d): Two@anonymous->a() #1 {main} thrown in %s on line 13 diff --git a/Zend/tests/object_types/return_type_inheritance_in_interface.phpt b/Zend/tests/object_types/return_type_inheritance_in_interface.phpt index 4c8f6c08af..793cc980aa 100644 --- a/Zend/tests/object_types/return_type_inheritance_in_interface.phpt +++ b/Zend/tests/object_types/return_type_inheritance_in_interface.phpt @@ -18,8 +18,8 @@ $three = new class implements Two { }; $three->a(); --EXPECTF-- -Fatal error: Uncaught TypeError: Return value of class@anonymous::a() must be an object, int returned in %s:13 +Fatal error: Uncaught TypeError: Return value of Two@anonymous::a() must be an object, int returned in %s:%d Stack trace: -#0 %s(16): class@anonymous->a() +#0 %s(%d): Two@anonymous->a() #1 {main} thrown in %s on line 13 diff --git a/Zend/tests/temporary_cleaning_013.phpt b/Zend/tests/temporary_cleaning_013.phpt index d9e7dd82f5..401edb512b 100644 --- a/Zend/tests/temporary_cleaning_013.phpt +++ b/Zend/tests/temporary_cleaning_013.phpt @@ -288,10 +288,10 @@ caught Exception 12 caught Exception 13 caught Exception 14 -Notice: Indirect modification of overloaded element of class@anonymous has no effect in %s on line %d +Notice: Indirect modification of overloaded element of ArrayAccess@anonymous has no effect in %s on line %d caught Exception 15 -Notice: Indirect modification of overloaded element of class@anonymous has no effect in %s on line %d +Notice: Indirect modification of overloaded element of ArrayAccess@anonymous has no effect in %s on line %d caught Exception 16 caught Exception 17 caught Exception 18 diff --git a/Zend/tests/type_declarations/typed_properties_065.phpt b/Zend/tests/type_declarations/typed_properties_065.phpt index d81b51d049..7a1dd54894 100644 --- a/Zend/tests/type_declarations/typed_properties_065.phpt +++ b/Zend/tests/type_declarations/typed_properties_065.phpt @@ -61,11 +61,11 @@ offsetSet(1e50) int(1) int(0) int(-1) -Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value +Cannot decrement a reference held by property ArrayAccess@anonymous::$foo of type int past its minimal value integer -Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value +Cannot decrement a reference held by property ArrayAccess@anonymous::$foo of type int past its minimal value integer -Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value +Cannot increment a reference held by property ArrayAccess@anonymous::$foo of type int past its maximal value integer -Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value +Cannot increment a reference held by property ArrayAccess@anonymous::$foo of type int past its maximal value integer diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 58fb3377d2..bc0a7dfdae 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6569,14 +6569,25 @@ void zend_compile_implements(zend_ast *ast) /* {{{ */ } /* }}} */ -static zend_string *zend_generate_anon_class_name(uint32_t start_lineno) /* {{{ */ +static zend_string *zend_generate_anon_class_name(zend_ast_decl *decl) { zend_string *filename = CG(active_op_array)->filename; - zend_string *result = zend_strpprintf(0, "class@anonymous%c%s:%" PRIu32 "$%" PRIx32, - '\0', ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++); + uint32_t start_lineno = decl->start_lineno; + + /* Use parent or first interface as prefix. */ + zend_string *prefix = ZSTR_KNOWN(ZEND_STR_CLASS); + if (decl->child[0]) { + prefix = zend_resolve_const_class_name_reference(decl->child[0], "class name"); + } else if (decl->child[1]) { + zend_ast_list *list = zend_ast_get_list(decl->child[1]); + prefix = zend_resolve_const_class_name_reference(list->child[0], "interface name"); + } + + zend_string *result = zend_strpprintf(0, "%s@anonymous%c%s:%" PRIu32 "$%" PRIx32, + ZSTR_VAL(prefix), '\0', ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++); + zend_string_release(prefix); return zend_new_interned_string(result); } -/* }}} */ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */ { @@ -6613,7 +6624,7 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */ zend_register_seen_symbol(lcname, ZEND_SYMBOL_CLASS); } else { - name = zend_generate_anon_class_name(decl->start_lineno); + name = zend_generate_anon_class_name(decl); lcname = zend_string_tolower(name); } lcname = zend_new_interned_string(lcname); diff --git a/ext/opcache/tests/bug78937_1.phpt b/ext/opcache/tests/bug78937_1.phpt index bc285f107b..0572e521aa 100644 --- a/ext/opcache/tests/bug78937_1.phpt +++ b/ext/opcache/tests/bug78937_1.phpt @@ -19,7 +19,7 @@ var_dump(foo()); --EXPECTF-- Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6 -Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 Fatal error: Anonymous class wasn't preloaded in %spreload_bug78937.inc on line 3 diff --git a/ext/opcache/tests/bug78937_2.phpt b/ext/opcache/tests/bug78937_2.phpt index a20c07d231..90aaa43883 100644 --- a/ext/opcache/tests/bug78937_2.phpt +++ b/ext/opcache/tests/bug78937_2.phpt @@ -20,6 +20,6 @@ var_dump(foo()); --EXPECTF-- Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6 -Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 -object(class@anonymous)#%d (0) { +Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +object(Bar@anonymous)#%d (0) { } diff --git a/ext/opcache/tests/bug78937_3.phpt b/ext/opcache/tests/bug78937_3.phpt index 16f7b80a40..81821e3109 100644 --- a/ext/opcache/tests/bug78937_3.phpt +++ b/ext/opcache/tests/bug78937_3.phpt @@ -18,7 +18,7 @@ var_dump(foo()); --EXPECTF-- Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6 -Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 Fatal error: Uncaught Error: Class 'Bar' not found in %spreload_bug78937.inc:3 Stack trace: diff --git a/ext/opcache/tests/bug78937_4.phpt b/ext/opcache/tests/bug78937_4.phpt index 2ad86870de..86c38a6d98 100644 --- a/ext/opcache/tests/bug78937_4.phpt +++ b/ext/opcache/tests/bug78937_4.phpt @@ -20,6 +20,6 @@ var_dump(new Foo); --EXPECTF-- Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6 -Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 Fatal error: Class foo wasn't preloaded in %spreload_bug78937.inc on line 6 diff --git a/ext/opcache/tests/bug78937_5.phpt b/ext/opcache/tests/bug78937_5.phpt index 3502699750..bb83408d90 100644 --- a/ext/opcache/tests/bug78937_5.phpt +++ b/ext/opcache/tests/bug78937_5.phpt @@ -21,6 +21,6 @@ var_dump(new Foo); --EXPECTF-- Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6 -Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 object(Foo)#%d (0) { } diff --git a/ext/opcache/tests/bug78937_6.phpt b/ext/opcache/tests/bug78937_6.phpt index ec1cc2d277..6e4d7060b3 100644 --- a/ext/opcache/tests/bug78937_6.phpt +++ b/ext/opcache/tests/bug78937_6.phpt @@ -19,7 +19,7 @@ var_dump(new Foo); --EXPECTF-- Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6 -Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 Fatal error: Uncaught Error: Class 'Bar' not found in %spreload_bug78937.inc:6 Stack trace: diff --git a/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt b/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt index 8671c2500b..df7fb42073 100644 --- a/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt +++ b/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt @@ -11,7 +11,7 @@ class Base {} $check = function () { $base = Base::class; foreach (get_declared_classes() as $class) { - if (strpos($class, 'class@anonymous') === false) { + if (strpos($class, '@anonymous') === false) { continue; } echo "Checking for $class\n"; @@ -30,6 +30,6 @@ echo "Done\n"; ?> --EXPECTF-- After first check -Checking for class@%s +Checking for Base@%s true Done diff --git a/ext/standard/tests/class_object/bug78638.phpt b/ext/standard/tests/class_object/bug78638.phpt index 088e7c4c1f..76315ee1c5 100644 --- a/ext/standard/tests/class_object/bug78638.phpt +++ b/ext/standard/tests/class_object/bug78638.phpt @@ -6,4 +6,4 @@ $c = new class('bar') extends __PHP_Incomplete_Class { }; ?> --EXPECTF-- -Fatal error: Class class@anonymous may not inherit from final class (__PHP_Incomplete_Class) in %sbug78638.php on line %d +Fatal error: Class __PHP_Incomplete_Class@anonymous may not inherit from final class (__PHP_Incomplete_Class) in %s on line %d diff --git a/ext/standard/tests/class_object/get_object_vars_variation_004.phpt b/ext/standard/tests/class_object/get_object_vars_variation_004.phpt index f52b3fed78e657ff79f51cccf9511fca5e21b002..902149ea0ac4cf780798c9ae4ca6d1063ca31d89 100644 GIT binary patch delta 49 mcmaFL`kQrw8DN&f>Hq0xe_`6 delta 31 ecmey(`jmBp8xw1CPGWKK