php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80305 Call with the splat operator ignores by reference requirements
Submitted: 2020-11-01 15:39 UTC Modified: 2020-11-01 16:32 UTC
From: greedy dot ivan at gmail dot com Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 7.4.12 OS: All
Private report: No CVE-ID: None
 [2020-11-01 15:39 UTC] greedy dot ivan at gmail dot com
Description:
------------
1. Passing arguments using the ... operator ignores requirements as to which arguments must be passed by reference.

2. Prevents warnings from subsequent calls that previously threw it (maybe it is some inner cache issue).

https://3v4l.org/ksVmp

Actually, there is a different behavior for 7.0, 7.3+, and 7.1 - 7.2.


Test script:
---------------
<?php

$foo = function (int &$bar) { $bar++; };
$baz = 0;
$args = [$baz];

call_user_func_array($foo, $args);
echo $args[0];

call_user_func_array($foo, $args);
echo $args[0];

$foo(...$args);
echo $args[0];

call_user_func_array($foo, $args);
echo $args[0];

call_user_func_array($foo, $args);
echo $args[0];

Expected result:
----------------
Warning: Parameter 1 to {closure}() expected to be a reference, value given in /in/ksVmp on line 7
0
Warning: Parameter 1 to {closure}() expected to be a reference, value given in /in/ksVmp on line 10
0
Warning: Parameter 1 to {closure}() expected to be a reference, value given in /in/ksVmp on line 13
0
Warning: Parameter 1 to {closure}() expected to be a reference, value given in /in/ksVmp on line 16
0
Warning: Parameter 1 to {closure}() expected to be a reference, value given in /in/ksVmp on line 19
0

Actual result:
--------------
Warning: Parameter 1 to {closure}() expected to be a reference, value given in /in/ksVmp on line 7
0
Warning: Parameter 1 to {closure}() expected to be a reference, value given in /in/ksVmp on line 10
0123

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-11-01 16:08 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Package: *General Issues +Package: Scripting Engine problem -Assigned To: +Assigned To: cmb
 [2020-11-01 16:08 UTC] cmb@php.net
> Passing arguments using the ... operator ignores requirements as
> to which arguments must be passed by reference.

The splat operator behaves as if the function was called
directly[1]; actually, it is call_user_func_array() which doesn't
behave correctly, but that is already filed as bug #70379.

[1] <https://3v4l.org/Ro4Mn>
 [2020-11-01 16:18 UTC] greedy dot ivan at gmail dot com
This is a second issue when using the splat operator modifies subsequent calls of call_user_func_array().

And this is a serious problem, because before this call, it does not change the argument that is not referenced, but starts doing it after.
 [2020-11-01 16:28 UTC] cmb@php.net
-Status: Not a bug +Status: Open -Assigned To: cmb +Assigned To:
 [2020-11-01 16:28 UTC] cmb@php.net
> This is a second issue when using the splat operator modifies
> subsequent calls of call_user_func_array().

Like I said, this is not particularly releated to the splat
operator, though.
 [2020-11-01 16:32 UTC] nikic@php.net
-Status: Open +Status: Not a bug
 [2020-11-01 16:32 UTC] nikic@php.net
The splat call creates a reference in the array, which also allows the following call_user_func_array() to work.
 [2020-11-01 17:18 UTC] greedy dot ivan at gmail dot com
This is very strange behavior and should be documented somehow. It doesn't change the argument itself -- it doesn't replace the value with a reference -- it does change some internal representation of the argument, which can actually start working with call_user_func_array().

And it's odd that the behavior of the code can be changed simply by calling some kind of operator with black magic inside.
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Tue Sep 28 17:03:37 2021 UTC