diff --git a/Zend/tests/anon/006.phpt b/Zend/tests/anon/006.phpt index 6bcd252dfc383..614a7a997e4e2 100644 --- a/Zend/tests/anon/006.phpt +++ b/Zend/tests/anon/006.phpt @@ -10,6 +10,6 @@ namespace { var_dump ($hello); } ?> ---EXPECTF-- -object(class@%s)#1 (0) { +--EXPECT-- +object(lone\@anonymous)#1 (0) { } diff --git a/Zend/tests/anon/007.phpt b/Zend/tests/anon/007.phpt index 166444b64f46c..0f01d759464e5 100644 --- a/Zend/tests/anon/007.phpt +++ b/Zend/tests/anon/007.phpt @@ -18,6 +18,6 @@ namespace lone { new Outer(); } ?> ---EXPECTF-- -object(class@%s)#2 (0) { +--EXPECT-- +object(lone\@anonymous)#2 (0) { } diff --git a/Zend/tests/anon_class_name.phpt b/Zend/tests/anon_class_name.phpt index 36f613d707b1c..ed0f40b3b5af1 100644 --- a/Zend/tests/anon_class_name.phpt +++ b/Zend/tests/anon_class_name.phpt @@ -23,8 +23,8 @@ namespace UsingNS { ?> --EXPECT-- -class@anonymous -DeclaringNS\Test1@anonymous -DeclaringNS\Test1@anonymous -DeclaringNS\Test2@anonymous -DeclaringNS\Test2@anonymous +UsingNS\@anonymous +UsingNS\@anonymous +UsingNS\@anonymous +UsingNS\@anonymous +UsingNS\@anonymous diff --git a/Zend/tests/deprecation_to_exception_during_inheritance.phpt b/Zend/tests/deprecation_to_exception_during_inheritance.phpt index dd0adec36a57c..1569f1770026d 100644 --- a/Zend/tests/deprecation_to_exception_during_inheritance.phpt +++ b/Zend/tests/deprecation_to_exception_during_inheritance.phpt @@ -17,7 +17,7 @@ $class = new class extends DateTime { ?> --EXPECTF-- -Fatal error: During inheritance of DateTime: Uncaught Exception: Return type of DateTime@anonymous::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in %s:%d +Fatal error: During inheritance of DateTime: Uncaught Exception: Return type of class@anonymous::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in %s:%d Stack trace: #0 %s(%d): {closure}(8192, 'Return type of ...', '%s', 8) #1 {main} in %s on line %d diff --git a/Zend/tests/generators/gh8289.phpt b/Zend/tests/generators/gh8289.phpt index f5bb1fc64be0b..4ffa6038305e1 100644 --- a/Zend/tests/generators/gh8289.phpt +++ b/Zend/tests/generators/gh8289.phpt @@ -28,7 +28,7 @@ foreach (yieldFromIteratorGeneratorThrows() as $k => $v) { int(1) Exception in %s:%d Stack trace: -#0 %s(%d): IteratorIterator@anonymous->key() +#0 %s(%d): class@anonymous->key() #1 %s(%d): yieldFromIteratorGeneratorThrows() #2 {main} int(2) diff --git a/Zend/tests/object_types/return_type_in_class.phpt b/Zend/tests/object_types/return_type_in_class.phpt index 3e441073737e3..0d21276afb1d3 100644 --- a/Zend/tests/object_types/return_type_in_class.phpt +++ b/Zend/tests/object_types/return_type_in_class.phpt @@ -19,8 +19,8 @@ $three = new class extends Two { $three->a(); ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Two@anonymous::a(): Return value must be of type object, int returned in %s:%d +Fatal error: Uncaught TypeError: class@anonymous::a(): Return value must be of type object, int returned in %s:%d Stack trace: -#0 %s(%d): Two@anonymous->a() +#0 %s(%d): class@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 6e2dbac55cf21..1047f109095a3 100644 --- a/Zend/tests/object_types/return_type_inheritance_in_class.phpt +++ b/Zend/tests/object_types/return_type_inheritance_in_class.phpt @@ -19,8 +19,8 @@ $three = new class extends Two { $three->a(); ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Two@anonymous::a(): Return value must be of type object, int returned in %s:%d +Fatal error: Uncaught TypeError: class@anonymous::a(): Return value must be of type object, int returned in %s:%d Stack trace: -#0 %s(%d): Two@anonymous->a() +#0 %s(%d): class@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 8bb5ad1616e9a..ccff2eaf8b3fe 100644 --- a/Zend/tests/object_types/return_type_inheritance_in_interface.phpt +++ b/Zend/tests/object_types/return_type_inheritance_in_interface.phpt @@ -19,8 +19,8 @@ $three = new class implements Two { $three->a(); ?> --EXPECTF-- -Fatal error: Uncaught TypeError: Two@anonymous::a(): Return value must be of type object, int returned in %s:%d +Fatal error: Uncaught TypeError: class@anonymous::a(): Return value must be of type object, int returned in %s:%d Stack trace: -#0 %s(%d): Two@anonymous->a() +#0 %s(%d): class@anonymous->a() #1 {main} thrown in %s on line 13 diff --git a/Zend/tests/record_errors_001.phpt b/Zend/tests/record_errors_001.phpt index dd3c0ba487ea0..962ad2b2b8bc4 100644 --- a/Zend/tests/record_errors_001.phpt +++ b/Zend/tests/record_errors_001.phpt @@ -16,4 +16,4 @@ new class extends DateTime { }; ?> --EXPECT-- -Error: Return type of DateTime@anonymous::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice +Error: Return type of class@anonymous::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice diff --git a/Zend/tests/temporary_cleaning_013.phpt b/Zend/tests/temporary_cleaning_013.phpt index e5f4b73bb14a2..be901744f5afb 100644 --- a/Zend/tests/temporary_cleaning_013.phpt +++ b/Zend/tests/temporary_cleaning_013.phpt @@ -301,10 +301,10 @@ caught Exception 13 Deprecated: Creation of dynamic property class@anonymous::$foo is deprecated in %s on line %d caught Exception 14 -Notice: Indirect modification of overloaded element of ArrayAccess@anonymous has no effect in %s on line %d +Notice: Indirect modification of overloaded element of class@anonymous has no effect in %s on line %d caught Exception 15 -Notice: Indirect modification of overloaded element of ArrayAccess@anonymous has no effect in %s on line %d +Notice: Indirect modification of overloaded element of class@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 a3a536da07e1c..d3a8a80cf726a 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 ArrayAccess@anonymous::$foo of type int past its minimal value +Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value integer -Cannot decrement a reference held by property ArrayAccess@anonymous::$foo of type int past its minimal value +Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value integer -Cannot increment a reference held by property ArrayAccess@anonymous::$foo of type int past its maximal value +Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value integer -Cannot increment a reference held by property ArrayAccess@anonymous::$foo of type int past its maximal value +Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value integer diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index cba90112cfc18..450dc721191b0 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7833,18 +7833,17 @@ static zend_string *zend_generate_anon_class_name(zend_ast_decl *decl) zend_string *filename = CG(active_op_array)->filename; uint32_t start_lineno = decl->start_lineno; - /* Use parent or first interface as prefix. */ + /* Use current_namespace\\ or "class" 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"); + const char *prefix_suffix = ""; + if (FC(current_namespace)) { + prefix = FC(current_namespace); + /* This is necessary to get the right short name of anonymous classes. */ + prefix_suffix = "\\"; } - 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); + zend_string *result = zend_strpprintf(0, "%s%s@anonymous%c%s:%" PRIu32 "$%" PRIx32, + ZSTR_VAL(prefix), prefix_suffix, '\0', ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++); return zend_new_interned_string(result); } diff --git a/ext/date/tests/bug65672.phpt b/ext/date/tests/bug65672.phpt index a3a4542e69db2..240e12d54c872 100644 --- a/ext/date/tests/bug65672.phpt +++ b/ext/date/tests/bug65672.phpt @@ -41,16 +41,16 @@ array(1) { } bool(false) -Deprecated: Creation of dynamic property DatePeriod@anonymous::$dynamic1 is deprecated in %s on line %d +Deprecated: Creation of dynamic property class@anonymous::$dynamic1 is deprecated in %s on line %d string(7) "dynamic" -Deprecated: Creation of dynamic property DatePeriod@anonymous::$dynamic2 is deprecated in %s on line %d +Deprecated: Creation of dynamic property class@anonymous::$dynamic2 is deprecated in %s on line %d array(1) { [0]=> string(5) "array" } -Deprecated: Creation of dynamic property DatePeriod@anonymous::$dynamic3 is deprecated in %s on line %d +Deprecated: Creation of dynamic property class@anonymous::$dynamic3 is deprecated in %s on line %d array(1) { [0]=> string(5) "array" diff --git a/ext/opcache/tests/bug78937_1.phpt b/ext/opcache/tests/bug78937_1.phpt index 657b306d68d4d..79f7423b2ef34 100644 --- a/ext/opcache/tests/bug78937_1.phpt +++ b/ext/opcache/tests/bug78937_1.phpt @@ -18,6 +18,6 @@ class Bar { var_dump(foo()); ?> --EXPECTF-- -Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 -object(Bar@anonymous)#%d (0) { +Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +object(class@anonymous)#1 (0) { } diff --git a/ext/opcache/tests/bug78937_2.phpt b/ext/opcache/tests/bug78937_2.phpt index eb359cee96bea..2cfccf31d88a0 100644 --- a/ext/opcache/tests/bug78937_2.phpt +++ b/ext/opcache/tests/bug78937_2.phpt @@ -19,6 +19,6 @@ class Bar { var_dump(foo()); ?> --EXPECTF-- -Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 -object(Bar@anonymous)#%d (0) { +Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +object(class@anonymous)#1 (0) { } diff --git a/ext/opcache/tests/bug78937_3.phpt b/ext/opcache/tests/bug78937_3.phpt index b17f8d0a08c3b..a3393aeaf2fcf 100644 --- a/ext/opcache/tests/bug78937_3.phpt +++ b/ext/opcache/tests/bug78937_3.phpt @@ -17,7 +17,7 @@ include(__DIR__ . "/preload_bug78937.inc"); var_dump(foo()); ?> --EXPECTF-- -Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +Warning: Can't preload unlinked class class@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 2598b5db9c166..6be21cd2d5d1a 100644 --- a/ext/opcache/tests/bug78937_4.phpt +++ b/ext/opcache/tests/bug78937_4.phpt @@ -19,6 +19,6 @@ bar(); var_dump(new Foo); ?> --EXPECTF-- -Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 object(Foo)#%d (0) { } diff --git a/ext/opcache/tests/bug78937_5.phpt b/ext/opcache/tests/bug78937_5.phpt index dc67b9045696b..e0395e2c0bf4d 100644 --- a/ext/opcache/tests/bug78937_5.phpt +++ b/ext/opcache/tests/bug78937_5.phpt @@ -20,6 +20,6 @@ bar(); var_dump(new Foo); ?> --EXPECTF-- -Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +Warning: Can't preload unlinked class class@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 fe9d5176aacb2..b86a57323906f 100644 --- a/ext/opcache/tests/bug78937_6.phpt +++ b/ext/opcache/tests/bug78937_6.phpt @@ -18,7 +18,7 @@ bar(); var_dump(new Foo); ?> --EXPECTF-- -Warning: Can't preload unlinked class Bar@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3 +Warning: Can't preload unlinked class class@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/php_reflection.c b/ext/reflection/php_reflection.c index 136d69b2864f4..3bb4bdb2fb138 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5397,6 +5397,24 @@ ZEND_METHOD(ReflectionClass, getExtensionName) } /* }}} */ +static const char *_class_get_namespace_backslash(const zend_class_entry *ce) +{ + const zend_string *name = ce->name; + size_t name_length; + + if (ce->ce_flags & ZEND_ACC_ANON_CLASS) { + /* Paths may contain backslashes. This is true on Linux and especially on Windows. + * Search first for '@' and then look for the first '\' before that. */ + const char *at = zend_memrchr(ZSTR_VAL(name), '@', ZSTR_LEN(name)); + ZEND_ASSERT(at != NULL); + name_length = at - ZSTR_VAL(name); + } else { + name_length = ZSTR_LEN(name); + } + + return zend_memrchr(ZSTR_VAL(name), '\\', name_length); +} + /* {{{ Returns whether this class is defined in namespace */ ZEND_METHOD(ReflectionClass, inNamespace) { @@ -5410,7 +5428,7 @@ ZEND_METHOD(ReflectionClass, inNamespace) GET_REFLECTION_OBJECT_PTR(ce); zend_string *name = ce->name; - const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); + const char *backslash = _class_get_namespace_backslash(ce); RETURN_BOOL(backslash && backslash > ZSTR_VAL(name)); } /* }}} */ @@ -5428,7 +5446,7 @@ ZEND_METHOD(ReflectionClass, getNamespaceName) GET_REFLECTION_OBJECT_PTR(ce); zend_string *name = ce->name; - const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); + const char *backslash = _class_get_namespace_backslash(ce); if (backslash && backslash > ZSTR_VAL(name)) { RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name)); } @@ -5449,7 +5467,7 @@ ZEND_METHOD(ReflectionClass, getShortName) GET_REFLECTION_OBJECT_PTR(ce); zend_string *name = ce->name; - const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); + const char *backslash = _class_get_namespace_backslash(ce); if (backslash && backslash > ZSTR_VAL(name)) { RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1)); } diff --git a/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt b/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt index f3701321fa7b4..5dcaf419812c9 100644 --- a/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt +++ b/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt @@ -34,6 +34,6 @@ echo "Done\n"; ?> --EXPECTF-- After first check -Checking for Base@%s +Checking for class@%s true Done diff --git a/ext/reflection/tests/gh12895.phpt b/ext/reflection/tests/gh12895.phpt new file mode 100644 index 0000000000000..eb8659c3577c6 --- /dev/null +++ b/ext/reflection/tests/gh12895.phpt @@ -0,0 +1,50 @@ +--TEST-- +GH-12895 (Incorrect ReflectionClass::getNamespaceName for anonymous class) +--FILE-- +getNamespaceName(), PHP_EOL; + echo 'getShortName: ', $rc->getShortName(), PHP_EOL; + echo 'inNamespace: ', $rc->inNamespace() ? "true" : "false", PHP_EOL; + echo "---\n"; + } +} + +?> +--EXPECTF-- +Class: Bar\@anonymous%s +getNamespaceName: Bar +getShortName: @anonymous%s +inNamespace: true +--- +Class: Bar\Baz\@anonymous%s +getNamespaceName: Bar\Baz +getShortName: @anonymous%s +inNamespace: true +--- +Class: class@anonymous%s +getNamespaceName: +getShortName: class@anonymous%s +inNamespace: false +--- diff --git a/ext/standard/tests/class_object/bug78638.phpt b/ext/standard/tests/class_object/bug78638.phpt index aaadcda836e71..3eadbde26e610 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 __PHP_Incomplete_Class@anonymous cannot extend final class __PHP_Incomplete_Class in %s on line %d +Fatal error: Class class@anonymous cannot extend 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 84827134c1b18..031b345e60ece 100644 --- a/ext/standard/tests/class_object/get_object_vars_variation_004.phpt +++ b/ext/standard/tests/class_object/get_object_vars_variation_004.phpt @@ -32,7 +32,7 @@ array(4) { [12]=> int(6) ["test"]=> - object(JsonSerializable@anonymous)#2 (0) { + object(class@anonymous)#2 (0) { } } array(4) { @@ -43,6 +43,6 @@ array(4) { [12]=> int(6) ["test"]=> - object(JsonSerializable@anonymous)#2 (0) { + object(class@anonymous)#2 (0) { } } diff --git a/ext/standard/tests/general_functions/get_debug_type_basic.phpt b/ext/standard/tests/general_functions/get_debug_type_basic.phpt index f630265e8cdbb..580c7466e8d53 100644 --- a/ext/standard/tests/general_functions/get_debug_type_basic.phpt +++ b/ext/standard/tests/general_functions/get_debug_type_basic.phpt @@ -45,8 +45,8 @@ namespace { ClassInGlobal Demo\ClassInNamespace class@anonymous -ToBeExtended@anonymous -ToBeImplemented@anonymous +class@anonymous +class@anonymous string bool bool