Commit a5d34b45a67 for php
commit a5d34b45a670bb70ea05e012d832b7186cdfda34
Author: Jorg Sowa <jorg.sowa@gmail.com>
Date: Thu Nov 12 15:45:37 2026 +0100
Fix AST export of property hook parameters and attributes (GH-25421)
set(int $v) => $v was exported as set => $v, and hook attributes were
dropped.
Closes GH-25421
diff --git a/NEWS b/NEWS
index 92cf423f60a..191b829f6f9 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,8 @@ PHP NEWS
. Fixed bug GH-25311 (Assertion ret == SUCCESS in array_map()/array_filter()
after delayed out-of-memory). (ndossche)
. Fixed AST export of by-reference property hooks. (Jorg Sowa)
+ . Fixed AST export of property hook parameter lists and attributes.
+ (Jorg Sowa)
- Curl:
. Fixed curl_reset() retaining CURLOPT_PRIVATE after reset. (lacatoire)
diff --git a/Zend/tests/property_hooks/ast_printing_params_attributes.phpt b/Zend/tests/property_hooks/ast_printing_params_attributes.phpt
new file mode 100644
index 00000000000..b5277c8c0a9
--- /dev/null
+++ b/Zend/tests/property_hooks/ast_printing_params_attributes.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Hook parameter list and attributes AST printing
+--FILE--
+<?php
+
+try {
+ assert(false && new class {
+ public int $prop1 {
+ set(int $value) => $value * 2;
+ }
+ public $prop2 {
+ #[A]
+ get => $this->prop2;
+ #[A(1), B]
+ #[C]
+ final set($value) {
+ $this->prop2 = $value;
+ }
+ }
+ public string $prop3 {
+ set(#[SensitiveParameter] string|int $value) => (string) $value;
+ }
+ public $prop4 {
+ #[A] final &get => $this->prop4;
+ }
+ public function __construct(
+ public int $prop5 {
+ #[A]
+ set(int $value) => $value + 1;
+ },
+ ) {}
+ });
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+assert(false && new class {
+ public int $prop1 {
+ set(int $value) => $value * 2;
+ }
+ public $prop2 {
+ #[A]
+ get => $this->prop2;
+ #[A(1), B]
+ #[C]
+ final set($value) {
+ $this->prop2 = $value;
+ }
+ }
+ public string $prop3 {
+ set(#[SensitiveParameter] string|int $value) => (string)$value;
+ }
+ public $prop4 {
+ #[A]
+ final &get => $this->prop4;
+ }
+ public function __construct(public int $prop5 {
+ #[A]
+ set(int $value) => $value + 1;
+ }) {
+ }
+
+})
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index 1fb4b8a28e4..e884ba897d8 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -2255,6 +2255,9 @@ static ZEND_COLD void zend_ast_export_hook_list(smart_str *str, const zend_ast_l
for (uint32_t i = 0; i < hook_list->children; i++) {
const zend_ast_decl *hook = (const zend_ast_decl *)hook_list->child[i];
+ if (hook->child[4]) {
+ zend_ast_export_attributes(str, hook->child[4], indent, 1);
+ }
if (hook->flags & ZEND_ACC_FINAL) {
smart_str_appends(str, "final ");
}
@@ -2262,6 +2265,11 @@ static ZEND_COLD void zend_ast_export_hook_list(smart_str *str, const zend_ast_l
smart_str_appendc(str, '&');
}
smart_str_append(str, hook->name);
+ if (hook->child[0]) {
+ smart_str_appendc(str, '(');
+ zend_ast_export_ex(str, hook->child[0], 0, indent);
+ smart_str_appendc(str, ')');
+ }
zend_ast *body = hook->child[2];
if (body == NULL) {
smart_str_appendc(str, ';');