From eaac77f4e7cb583670828eec93c8ba1491d2961b Mon Sep 17 00:00:00 2001 From: Go Kudo Date: Tue, 31 Aug 2021 18:56:39 +0900 Subject: [PATCH] Fix nested namespaced typed property in gen_stub.php (#7418) Property escape namespaced class name in property types. --- build/gen_stub.php | 18 ++++++++++++++---- ext/zend_test/test.stub.php | 2 ++ ext/zend_test/test_arginfo.h | 9 ++++++++- ext/zend_test/tests/gen_stub_test_01.phpt | 22 ++++++++++++++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 ext/zend_test/tests/gen_stub_test_01.phpt diff --git a/build/gen_stub.php b/build/gen_stub.php index 77d6fe3f6f3..c499912f424 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -395,6 +395,11 @@ class SimpleType { return str_replace('\\', '\\\\', $this->name); } + public function toCVarEscapedName(): string { + $name = str_replace('_', '__', $this->name); + return str_replace('\\', '_', $this->name); + } + public function equals(SimpleType $other): bool { return $this->name === $other->name && $this->isBuiltin === $other->isBuiltin; } @@ -1374,7 +1379,9 @@ class PropertyInfo if (count($arginfoType->classTypes) >= 2) { foreach ($arginfoType->classTypes as $classType) { $className = $classType->name; - $code .= "\tzend_string *property_{$propertyName}_class_{$className} = zend_string_init(\"$className\", sizeof(\"$className\") - 1, 1);\n"; + $escapedClassName = $classType->toEscapedName(); + $varEscapedClassName = $classType->toCVarEscapedName(); + $code .= "\tzend_string *property_{$propertyName}_class_{$varEscapedClassName} = zend_string_init(\"{$escapedClassName}\", sizeof(\"{$escapedClassName}\") - 1, 1);\n"; } $classTypeCount = count($arginfoType->classTypes); @@ -1383,7 +1390,8 @@ class PropertyInfo foreach ($arginfoType->classTypes as $k => $classType) { $className = $classType->name; - $code .= "\tproperty_{$propertyName}_type_list->types[$k] = (zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$className}, 0, 0);\n"; + $escapedClassName = $classType->toEscapedName(); + $code .= "\tproperty_{$propertyName}_type_list->types[$k] = (zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$escapedClassName}, 0, 0);\n"; } $typeMaskCode = $this->type->toArginfoType()->toTypeMask(); @@ -1392,9 +1400,11 @@ class PropertyInfo $typeCode = "property_{$propertyName}_type"; } else { $className = $arginfoType->classTypes[0]->name; - $code .= "\tzend_string *property_{$propertyName}_class_{$className} = zend_string_init(\"$className\", sizeof(\"$className\")-1, 1);\n"; + $escapedClassName = $arginfoType->classTypes[0]->toEscapedName(); + $varEscapedClassName = $arginfoType->classTypes[0]->toCVarEscapedName(); + $code .= "\tzend_string *property_{$propertyName}_class_{$varEscapedClassName} = zend_string_init(\"{$escapedClassName}\", sizeof(\"${escapedClassName}\")-1, 1);\n"; - $typeCode = "(zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$className}, 0, " . $arginfoType->toTypeMask() . ")"; + $typeCode = "(zend_type) ZEND_TYPE_INIT_CLASS(property_{$propertyName}_class_{$varEscapedClassName}, 0, " . $arginfoType->toTypeMask() . ")"; } } else { $typeCode = "(zend_type) ZEND_TYPE_INIT_MASK(" . $arginfoType->toTypeMask() . ")"; diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index a8f8f6a7b68..179c5389d9b 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -88,6 +88,8 @@ namespace ZendTestNS { namespace ZendTestNS2 { class Foo { + public ZendSubNS\Foo $foo; + public function method(): void {} } diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 5d6dbd49630..ca094e36169 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 93bb8b9120e510e8c3afc29dc0a5d47cb6b5f10e */ + * Stub hash: 04d48fa64594bacba57210dcb94381f83951116c */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -296,6 +296,13 @@ static zend_class_entry *register_class_ZendTestNS2_Foo(void) INIT_NS_CLASS_ENTRY(ce, "ZendTestNS2", "Foo", class_ZendTestNS2_Foo_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); + zend_string *property_foo_class_ZendTestNS2_ZendSubNS_Foo = zend_string_init("ZendTestNS2\\ZendSubNS\\Foo", sizeof("ZendTestNS2\\ZendSubNS\\Foo")-1, 1); + zval property_foo_default_value; + ZVAL_UNDEF(&property_foo_default_value); + zend_string *property_foo_name = zend_string_init("foo", sizeof("foo") - 1, 1); + zend_declare_typed_property(class_entry, property_foo_name, &property_foo_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_foo_class_ZendTestNS2_ZendSubNS_Foo, 0, 0)); + zend_string_release(property_foo_name); + return class_entry; } diff --git a/ext/zend_test/tests/gen_stub_test_01.phpt b/ext/zend_test/tests/gen_stub_test_01.phpt new file mode 100644 index 00000000000..8b13cbaa034 --- /dev/null +++ b/ext/zend_test/tests/gen_stub_test_01.phpt @@ -0,0 +1,22 @@ +--TEST-- +gen_stub.php: nested namespaced typed properties test. +--EXTENSIONS-- +zend_test +--FILE-- +foo = new \ZendTestNS2\ZendSubNS\Foo(); +var_dump($foo); +?> +--EXPECTF-- +object(ZendTestNS2\Foo)#%d (%d) { + ["foo"]=> + uninitialized(ZendTestNS2\ZendSubNS\Foo) +} +object(ZendTestNS2\Foo)#%d (%d) { + ["foo"]=> + object(ZendTestNS2\ZendSubNS\Foo)#%d (%d) { + } +}