Commit 9cf418231ea for php.net
commit 9cf418231ea3e47753a35ccc7b8dca1cd3a3adcb
Author: Jérôme Tamarelle <jerome@tamarelle.net>
Date: Fri Apr 17 22:39:32 2026 +0200
gen_stub: fix invalid C variable name for namespaced types in union/intersection type list (#21717)
When generating a union or intersection type list with multiple class
types, the variable holding each zend_string* was declared using
toVarEscapedName() (backslashes replaced by underscores), but the
subsequent ZEND_TYPE_INIT_CLASS() reference used toEscapedName()
(backslashes escaped as \\), producing an invalid C identifier.
Backported to PHP 8.5.
diff --git a/build/gen_stub.php b/build/gen_stub.php
index 67be5c2f7b9..52ddb4d36f8 100755
--- a/build/gen_stub.php
+++ b/build/gen_stub.php
@@ -2511,8 +2511,8 @@ protected function getTypeCode(string $variableLikeName, string &$code): string
$code .= "\t{$variableLikeType}_{$variableLikeName}_type_list->num_types = $classTypeCount;\n";
foreach ($arginfoType->classTypes as $k => $classType) {
- $escapedClassName = $classType->toEscapedName();
- $code .= "\t{$variableLikeType}_{$variableLikeName}_type_list->types[$k] = (zend_type) ZEND_TYPE_INIT_CLASS({$variableLikeType}_{$variableLikeName}_class_{$escapedClassName}, 0, 0);\n";
+ $varEscapedClassName = $classType->toVarEscapedName();
+ $code .= "\t{$variableLikeType}_{$variableLikeName}_type_list->types[$k] = (zend_type) ZEND_TYPE_INIT_CLASS({$variableLikeType}_{$variableLikeName}_class_{$varEscapedClassName}, 0, 0);\n";
}
$typeMaskCode = $this->type->toArginfoType()->toTypeMask();
diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index bcacc85caa1..310386dd42d 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -67,6 +67,7 @@ static zend_class_entry *zend_test_forbid_dynamic_call;
static zend_class_entry *zend_test_ns_foo_class;
static zend_class_entry *zend_test_ns_unlikely_compile_error_class;
static zend_class_entry *zend_test_ns_not_unlikely_compile_error_class;
+static zend_class_entry *zend_test_ns_bar_class;
static zend_class_entry *zend_test_ns2_foo_class;
static zend_class_entry *zend_test_ns2_ns_foo_class;
static zend_class_entry *zend_test_unit_enum;
@@ -1488,6 +1489,7 @@ PHP_MINIT_FUNCTION(zend_test)
zend_test_ns_foo_class = register_class_ZendTestNS_Foo();
zend_test_ns_unlikely_compile_error_class = register_class_ZendTestNS_UnlikelyCompileError();
zend_test_ns_not_unlikely_compile_error_class = register_class_ZendTestNS_NotUnlikelyCompileError();
+ zend_test_ns_bar_class = register_class_ZendTestNS_Bar();
zend_test_ns2_foo_class = register_class_ZendTestNS2_Foo();
zend_test_ns2_ns_foo_class = register_class_ZendTestNS2_ZendSubNS_Foo();
diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php
index b0fca4cc2b9..472ba9f3ddf 100644
--- a/ext/zend_test/test.stub.php
+++ b/ext/zend_test/test.stub.php
@@ -361,6 +361,8 @@ class Foo {
public function method(): int {}
}
+ interface Bar {}
+
class UnlikelyCompileError {
/* This method signature would create a compile error due to the string
* "ZendTestNS\UnlikelyCompileError" in the generated macro call */
@@ -381,6 +383,8 @@ public function method(): ?NotUnlikelyCompileError {}
class Foo {
public ZendSubNS\Foo $foo;
+ public ZendSubNS\Foo&\ZendTestNS\Bar $intersectionProp;
+ public ZendSubNS\Foo|\ZendTestNS\Bar $unionProp;
public function method(): void {}
}
diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h
index eca1b91f6bf..3834ae1fc21 100644
Binary files a/ext/zend_test/test_arginfo.h and b/ext/zend_test/test_arginfo.h differ
diff --git a/ext/zend_test/tests/gen_stub_test_01.phpt b/ext/zend_test/tests/gen_stub_test_01.phpt
index 0f5d525322d..3126eb61631 100644
--- a/ext/zend_test/tests/gen_stub_test_01.phpt
+++ b/ext/zend_test/tests/gen_stub_test_01.phpt
@@ -18,11 +18,19 @@
object(ZendTestNS2\Foo)#%d (%d) {
["foo"]=>
uninitialized(ZendTestNS2\ZendSubNS\Foo)
+ ["intersectionProp"]=>
+ uninitialized(ZendTestNS2\ZendSubNS\Foo&ZendTestNS\Bar)
+ ["unionProp"]=>
+ uninitialized(ZendTestNS2\ZendSubNS\Foo|ZendTestNS\Bar)
}
object(ZendTestNS2\Foo)#%d (%d) {
["foo"]=>
object(ZendTestNS2\ZendSubNS\Foo)#%d (%d) {
}
+ ["intersectionProp"]=>
+ uninitialized(ZendTestNS2\ZendSubNS\Foo&ZendTestNS\Bar)
+ ["unionProp"]=>
+ uninitialized(ZendTestNS2\ZendSubNS\Foo|ZendTestNS\Bar)
}
object(ZendTestNS\UnlikelyCompileError)#%d (%d) {
}