Commit dee1317c333 for php.net

commit dee1317c3334ca624bab6b03b3e4e0c64e90c0a5
Author: Tim Düsterhus <tim@bastelstu.be>
Date:   Tue Jun 16 00:14:37 2026 +0200

    zend_ast: Always print encaps list variables with braces when exporting AST (#22293)

    The `"{$foo}"` variant of interpolating variables into a string is the only one
    that reliably works all the time. Always use it for simplicity.

    Fixes php/php-src#22291.

diff --git a/NEWS b/NEWS
index efc85058719..e947b61b9d4 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,8 @@ PHP                                                                        NEWS
     (kocsismate)
   . Fixed bug GH-22292 (AST pretty printing does not correctly handle
     invalid variable names). (timwolla)
+  . Fixed bug GH-22291 (AST pretty printing does not correctly handle braces
+    in string interpolation). (timwolla)

 - BCMath:
   . Added NUL-byte validation to BCMath functions. (jorgsowa)
diff --git a/Zend/tests/assert/expect_015.phpt b/Zend/tests/assert/expect_015.phpt
index 79ea3703ead..3bb08504f58 100644
--- a/Zend/tests/assert/expect_015.phpt
+++ b/Zend/tests/assert/expect_015.phpt
@@ -201,7 +201,7 @@ private static function f1() {
                 $s[$i] = $a[$j];
             }
             foreach ($a as $key => &$val) {
-                print "$key => $val\n";
+                print "{$key} => {$val}\n";
             }
             while ($s[$i]) {
                 $i++;
@@ -299,12 +299,12 @@ class A {
         echo 1;
     }
     $x = '\'"`$a';
-    $x = "'\"`$a";
-    $x = `'"\`$a`;
+    $x = "'\"`{$a}";
+    $x = `'"\`{$a}`;
     $x = "{$a}b";
     $x = "{$a}b";
     $x = " {$foo->bar} {${$foo->bar}} ";
-    $x = " ${'---'} ";
+    $x = " {${'---'}} ";
     foo();
     \foo();
     namespace\foo();
diff --git a/Zend/tests/assert/expect_020.phpt b/Zend/tests/assert/expect_020.phpt
index d305667a28d..2146abc9604 100644
--- a/Zend/tests/assert/expect_020.phpt
+++ b/Zend/tests/assert/expect_020.phpt
@@ -16,5 +16,5 @@
 --EXPECT--
 assert(): assert(0 && ($a = function () {
     $var = 'test';
-    $str = "$var, {$var[1]}, {$var}[], {$var[1]}[], {$var}[], {$var[1]}[]";
+    $str = "{$var}, {$var[1]}, {$var}[], {$var[1]}[], {$var}[], {$var[1]}[]";
 })) failed
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index 983299c0a9d..c908f6b18c7 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -1675,19 +1675,6 @@ static ZEND_COLD void zend_ast_export_ns_name(smart_str *str, zend_ast *ast, int
 	zend_ast_export_ex(str, ast, priority, indent);
 }

-static ZEND_COLD bool zend_ast_valid_var_char(char ch)
-{
-	unsigned char c = (unsigned char)ch;
-
-	if (c != '_' && c < 127 &&
-	    (c < '0' || c > '9') &&
-	    (c < 'A' || c > 'Z') &&
-	    (c < 'a' || c > 'z')) {
-		return false;
-	}
-	return true;
-}
-
 static ZEND_COLD bool zend_ast_valid_var_name(const char *s, size_t len)
 {
 	unsigned char c;
@@ -1714,11 +1701,6 @@ static ZEND_COLD bool zend_ast_valid_var_name(const char *s, size_t len)
 	return true;
 }

-static ZEND_COLD bool zend_ast_var_needs_braces(char ch)
-{
-	return ch == '[' || zend_ast_valid_var_char(ch);
-}
-
 static ZEND_COLD void zend_ast_export_var(smart_str *str, zend_ast *ast, int indent)
 {
 	if (ast->kind == ZEND_AST_ZVAL) {
@@ -1775,14 +1757,6 @@ static ZEND_COLD void zend_ast_export_encaps_list(smart_str *str, char quote, co

 			ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
 			zend_ast_export_qstr(str, quote, Z_STR_P(zv));
-		} else if (ast->kind == ZEND_AST_VAR &&
-		           ast->child[0]->kind == ZEND_AST_ZVAL &&
-		           (i + 1 == list->children ||
-		            list->child[i + 1]->kind != ZEND_AST_ZVAL ||
-		            !zend_ast_var_needs_braces(
-		                *Z_STRVAL_P(
-		                    zend_ast_get_zval(list->child[i + 1]))))) {
-			zend_ast_export_ex(str, ast, 0, indent);
 		} else {
 			smart_str_appendc(str, '{');
 			zend_ast_export_ex(str, ast, 0, indent);
diff --git a/ext/standard/tests/assert/gh22291.phpt b/ext/standard/tests/assert/gh22291.phpt
new file mode 100644
index 00000000000..a50bd5861f0
--- /dev/null
+++ b/ext/standard/tests/assert/gh22291.phpt
@@ -0,0 +1,19 @@
+--TEST--
+GH-22291: AST pretty printing does not correctly handle braces in string interpolation
+--FILE--
+<?php
+
+try {
+	$foo = 'abc';
+	var_dump("{{$foo}}");
+	var_dump("{$foo}");
+	assert(!"{{$foo}}");
+} catch (Error $e) {
+	echo $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECT--
+string(5) "{abc}"
+string(3) "abc"
+assert(!"{{$foo}}")