]> granicus.if.org Git - php/commitdiff
Improve generated names for anonymous classes
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 6 Feb 2020 10:13:13 +0000 (11:13 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 17 Feb 2020 11:21:33 +0000 (12:21 +0100)
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.

17 files changed:
UPGRADING
Zend/tests/anon_class_name.phpt [new file with mode: 0644]
Zend/tests/object_types/return_type_in_class.phpt
Zend/tests/object_types/return_type_inheritance_in_class.phpt
Zend/tests/object_types/return_type_inheritance_in_interface.phpt
Zend/tests/temporary_cleaning_013.phpt
Zend/tests/type_declarations/typed_properties_065.phpt
Zend/zend_compile.c
ext/opcache/tests/bug78937_1.phpt
ext/opcache/tests/bug78937_2.phpt
ext/opcache/tests/bug78937_3.phpt
ext/opcache/tests/bug78937_4.phpt
ext/opcache/tests/bug78937_5.phpt
ext/opcache/tests/bug78937_6.phpt
ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt
ext/standard/tests/class_object/bug78638.phpt
ext/standard/tests/class_object/get_object_vars_variation_004.phpt

index 30611b10132190c8aed92d12e8eae496b988f452..5174a2e52f6f101f02f7a1260e7e9775ee02fab7 100644 (file)
--- 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 (file)
index 0000000..36f613d
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Generated names for anonymous classes
+--FILE--
+<?php
+
+namespace DeclaringNS {
+    class Test1 {}
+    interface Test2 {}
+    interface Test3 {}
+}
+
+namespace UsingNS {
+    function print_name(object $obj) {
+        echo strstr(get_class($obj), "\0", true), "\n";
+    }
+
+    print_name(new class {});
+    print_name(new class extends \DeclaringNS\Test1 {});
+    print_name(new class extends \DeclaringNS\Test1 implements \DeclaringNS\Test2 {});
+    print_name(new class implements \DeclaringNS\Test2 {});
+    print_name(new class implements \DeclaringNS\Test2, \DeclaringNS\Test3 {});
+}
+
+?>
+--EXPECT--
+class@anonymous
+DeclaringNS\Test1@anonymous
+DeclaringNS\Test1@anonymous
+DeclaringNS\Test2@anonymous
+DeclaringNS\Test2@anonymous
index c4c1dc05160ee66c2a3573f2600636bd745c921b..3edb015df756c6eaa8256d0732481e821fa30222 100644 (file)
@@ -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
index a7316136fb778ec9c52db5a03c0d97853d84e920..23528531ec56328c619e9117b05c60206ec6d29d 100644 (file)
@@ -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
index 4c8f6c08affbbaf83700a344cc5e5a8347a88262..793cc980aa6ae9bb6f57cc3a72b7bb9880e6bdfc 100644 (file)
@@ -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
index d9e7dd82f5c7c58178b9ad2fc907eb1a9a1f6fde..401edb512b97e947406f9881031adf555bf23777 100644 (file)
@@ -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
index d81b51d049d6438d746cf4dfe094182f75261ca2..7a1dd54894b346e01531fbc6d6fd1b5905dda066 100644 (file)
@@ -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
index 58fb3377d2cfc4a653b31e74d6b049d446051416..bc0a7dfdaeacfbceda4220982811b6c97218af3b 100644 (file)
@@ -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);
index bc285f107b98d504381b0aab281ddb723b237926..0572e521aa53d1c951a0ae59e7a4b8b5d885dc2a 100644 (file)
@@ -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
 
index a20c07d231e3f8e19b07157452184f1cccb1ae42..90aaa4388341bd8f5c3f92c62c514018587a6634 100644 (file)
@@ -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) {
 }
index 16f7b80a4035f1b5cd691b68888eab8810b043bb..81821e3109a75946a45519e5be74049248a71eeb 100644 (file)
@@ -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:
index 2ad86870de85bf9425eb2a547f28637ec1b66f63..86c38a6d98f4e8409a15817433d83139851135db 100644 (file)
@@ -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
index 3502699750e39cf9e4ff5b2b522a043343aee0dc..bb83408d90e36e26f042e7b521909deb1604dfd9 100644 (file)
@@ -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) {
 }
index ec1cc2d2772a52c147877d0cfc6814bc819ecb7f..6e4d7060b3c761336c8c1f594e015d29d690aa0d 100644 (file)
@@ -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:
index 8671c2500bd541158f3da5ae7f9db49e04043c42..df7fb4207333cfcd4873c4ac3de90e3e6b62c083 100644 (file)
@@ -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
index 088e7c4c1f083f56fac75b9e06d684f4e15269c9..76315ee1c568a5657a01df5292d2d1e679e61dd0 100644 (file)
@@ -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
index f52b3fed78e657ff79f51cccf9511fca5e21b002..902149ea0ac4cf780798c9ae4ca6d1063ca31d89 100644 (file)
Binary files a/ext/standard/tests/class_object/get_object_vars_variation_004.phpt and b/ext/standard/tests/class_object/get_object_vars_variation_004.phpt differ