php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #64693 Third argument ($initial) passed to array_reduce should be immutable.
Submitted: 2013-04-22 19:41 UTC Modified: 2013-04-23 15:54 UTC
From: jdoane at vlacs dot org Assigned:
Status: Not a bug Package: Arrays related
PHP Version: 5.3.24 OS: Ubuntu 12.04.02 LTS
Private report: No CVE-ID: None
 [2013-04-22 19:41 UTC] jdoane at vlacs dot org
Description:
------------
When array_reduce is called with an object as the third argument, the variable 
passed to said third argument will turn into the result of the array_reduce() 
call. It feels like the object getting passed into array_reduce is not being 
cloned and is being modified in place. Since all objects are passed as a reference 
it changes the "$initial" variable in the scope where array_reduce was called.

So either documentation needs to be updated that says that $initial gets set to 
the return value when it is an object or this shouldn't happen to begin with as it 
appears that $initial should remain immutable for the duration of the 
array_reduce() call.

Test script:
---------------
$array = (object)Array('foo', 'baraz');
$initial = (object)Array('count' => 0, 'maxlen' => 0);
$output = array_reduce($array, function(&$d, $item) {
    if($d->maxlen < strlen($d)) { $d->maxlen = strlen($d); }
    $d->count++;
    return $d;
}
print_r($output);
print_r($initial);

Expected result:
----------------
~$ php test.php
stdClass Object
(
    [count] => 0
    [maxlen] => 0
)
stdClass Object
(
    [count] => 2
    [maxlen] => 5
)

Actual result:
--------------
~$ php test.php
stdClass Object
(
    [count] => 2
    [maxlen] => 5
)
stdClass Object
(
    [count] => 2
    [maxlen] => 5
)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-04-23 13:04 UTC] jdoane at vlacs dot org
-Summary: Third argument passed to array_reduce turned into return value +Summary: Third argument ($initial) passed to array_reduce should be immutable.
 [2013-04-23 13:04 UTC] jdoane at vlacs dot org
The order of the expected output is backwards, I apologize.

It should be:
~$ php test.php
stdClass Object
(
    [count] => 2
    [maxlen] => 5
)
stdClass Object
(
    [count] => 0
    [maxlen] => 0
)
 [2013-04-23 15:27 UTC] nikic@php.net
array_reduce uses the normal passing semantics. We do not document for every function that it uses the normal passing semantics, because, well, they are the same everywhere.

PHP never clones your objects unless you tell it to.
 [2013-04-23 15:27 UTC] nikic@php.net
-Status: Open +Status: Not a bug
 [2013-04-23 15:54 UTC] jdoane at vlacs dot org
So you're telling me that the inconsistent behavior is not due to the poor implementation of array_reduce() but rather of PHP? So even though things by name imply that a variable is immutable (hence $initial, you do know what initial means, right?) that the resulting mutation will make it something other than the initial value?

Thank you for clarifying that for me, but you leave me baffled as to your reasoning why this seems like a good idea. Maybe it's not a bug, but it's definitely not clean and consistent. Consider saying that a variable is an "initial" value, you would think that it would remain an initial value, hence implying the value (regardless of type) is immutable.
 [2013-10-07 00:45 UTC] a at b dot c dot de
"Normal passing semantics" refers not only to the pass-by-value semantics of PHP, but also to many OO-based languages such as Java and C#: changing an object's properties inside a function will change the properties of the object - the object itself remains the same object and doesn't get cloned or replaced in the process.

Of course, if you explicitly pass the object by reference as you do in your sample code then the behaviour changes in a way similar to C#'s ref signature modifier.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 26 11:01:31 2024 UTC