Repository: php/php-src (2025-08-14T11:24:49Z)

Issue:
pipe operator (`|>`) fails to correctly handle returning by reference
### Description

There appears to be a bug in how the new pipe operator (`|>`) handles functions that return by reference. An expression using the pipe operator is not behaving identically to its equivalent standard function call, specifically when a reference is expected to be returned.

The expression `"foo" |> get_ref(...)` should, in theory, be functionally equivalent to `$c = get_ref(...); $c("foo");`. However, the two produce different results when the function is declared to return a reference.

This code correctly returns a reference to the static variable within `get_ref` without any errors ( https://3v4l.org/Ojaah ):

```php
<?php

function &get_ref($_): string {
    static $a = "f";
    return $a;
}


function &get_ref2(): string {
    $c = get_ref(...);    
    return  $c("foo");
}

echo get_ref2();
```

This version, which should be equivalent, incorrectly throws a notice ( https://3v4l.org/po5A6 ):

```php
<?php

function &get_ref($_): string {
    static $a = "f";
    return $a;
}


function &get_ref2(): string {
    return "foo" |> get_ref(...);
}

echo get_ref2();
```

### PHP Version

```plain
master
```

### Operating System

N/A


Discussion:

Patch:
diff --git a/NEWS b/NEWS
index 77c1e32ff3a82..0180f5b3478a6 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ PHP                                                                        NEWS
 - Core:
   . Fixed bug GH-18850 (Repeated inclusion of file with __halt_compiler()
     triggers "Constant already defined" warning). (ilutov)
+  . Fixed bug GH-19476 (pipe operator fails to correctly handle returning
+    by reference). (alexandre-daubois)
 
 - ODBC:
   . Remove ODBCVER and assume ODBC 3.5. (Calvin Buckley)
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index db611be49ab45..aba735124a0a5 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -2726,7 +2726,8 @@ static inline bool zend_is_call(zend_ast *ast) /* {{{ */
 	return ast->kind == ZEND_AST_CALL
 		|| ast->kind == ZEND_AST_METHOD_CALL
 		|| ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL
-		|| ast->kind == ZEND_AST_STATIC_CALL;
+		|| ast->kind == ZEND_AST_STATIC_CALL
+		|| ast->kind == ZEND_AST_PIPE;
 }
 /* }}} */
 


Test patch:
diff --git a/Zend/tests/pipe_operator_reference_context.phpt b/Zend/tests/pipe_operator_reference_context.phpt
new file mode 100644
index 0000000000000..7d7572e2b2e59
--- /dev/null
+++ b/Zend/tests/pipe_operator_reference_context.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Fix GH-19476: Pipe operator with function returning by reference
+--FILE--
+<?php
+
+function &get_ref($_): string {
+    static $a = "original";
+
+    $a .= " ".$_;
+
+    return $a;
+}
+
+function &test_pipe_ref(): string {
+    return "input" |> get_ref(...);
+}
+
+$ref = &test_pipe_ref();
+echo "Before: " . $ref . "\n";
+$ref = "changed";
+echo "After: " . test_pipe_ref() . "\n";
+
+?>
+--EXPECT--
+Before: original input
+After: changed input