php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #53438 array_fill/array_fill_keys don't run constructors multiple times
Submitted: 2010-12-01 17:56 UTC Modified: 2010-12-02 17:42 UTC
From: alxndr+bugs dot php dot net at gmail dot com Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: 5.3.3 OS: Ubuntu 10.10
Private report: No CVE-ID: None
 [2010-12-01 17:56 UTC] alxndr+bugs dot php dot net at gmail dot com
Description:
------------
array_fill() and array_fill_keys() create arrays filled with the same value, with 
unique copies in each value. However if that value is a class, it appears that 
they are all referencing just one value. That is, modifying a value of an array 
created with array_fill/array_fill_keys will modify all the values if that value 
is a class. It is as if the new class construction occurs once, and the result is 
placed in all values of the array being created (whereas if the value were to be 
an integer, string, or array, each value in the created array would be independent 
of the others).

Test script:
---------------
$arr1 = array_fill( 0, 2, array('foo') );
print "\narr1 after array_fill() with array as a value:\n".print_r($arr1,true);
array_push($arr1[0],'bar');
print "\narr1 after pushing a string onto the first of the arrays in it:\n".print_r($arr1,true);

class Test {
    public $storage = array();
    public function __construct($p=null) {
        $this->add($p);
    }
    public function add($p=null) {
        if ($p)
            $this->storage[] = $p;
    }
}

$arr2 = array_fill(0, 2, new Test('foo') );
print "\narr2 after array_fill() with new Test as a value:\n".print_r($arr2,true);
$arr2[0]->add('bar');
print "\narr2 after adding to the first object in it:\n".print_r($arr2,true);


Expected result:
----------------
arr1 after array_fill() with array as a value:
Array
(
    [0] => Array
        (
            [0] => foo
        )

    [1] => Array
        (
            [0] => foo
        )

)

arr1 after pushing a string onto the first of the arrays in it:
Array
(
    [0] => Array
        (
            [0] => foo
            [1] => bar
        )

    [1] => Array
        (
            [0] => foo
        )

)

arr2 after array_fill() with new Test as a value:
Array
(
    [0] => Test Object
        (
            [storage] => Array
                (
                    [0] => foo
                )

        )

    [1] => Test Object
        (
            [storage] => Array
                (
                    [0] => foo
                )

        )

)

arr2 after adding to the first object in it:
Array
(
    [0] => Test Object
        (
            [storage] => Array
                (
                    [0] => foo
                    [1] => bar
                )

        )

    [1] => Test Object
        (
            [storage] => Array
                (
                    [0] => foo
                )

        )

)


Actual result:
--------------
arr1 after array_fill() with array as a value:
Array
(
    [0] => Array
        (
            [0] => foo
        )

    [1] => Array
        (
            [0] => foo
        )

)

arr1 after pushing a string onto the first of the arrays in it:
Array
(
    [0] => Array
        (
            [0] => foo
            [1] => bar
        )

    [1] => Array
        (
            [0] => foo
        )

)

arr2 after array_fill() with new Test as a value:
Array
(
    [0] => Test Object
        (
            [storage] => Array
                (
                    [0] => foo
                )

        )

    [1] => Test Object
        (
            [storage] => Array
                (
                    [0] => foo
                )

        )

)

arr2 after adding to the first object in it:
Array
(
    [0] => Test Object
        (
            [storage] => Array
                (
                    [0] => foo
                    [1] => bar
                )

        )

    [1] => Test Object
        (
            [storage] => Array
                (
                    [0] => foo
                    [1] => bar
                )

        )

)


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-12-02 11:34 UTC] johannes@php.net
-Status: Open +Status: Bogus
 [2010-12-02 11:34 UTC] johannes@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

function parameters are evaluated before a function call. There's no implicit clone happening. All expected.
 [2010-12-02 17:42 UTC] alxndr+bugs dot php dot net at gmail dot com
I had a hunch it would be something like that. Out of curiosity, is there a way to do this sort of thing with array_fill? It can be kludged with a foreach*, but it seems that this is what array_fill/array_fill_keys should be for...

* e.g.
class T {
  private $t = array();
  function add($p) { $this->t[] = $p; }
}
$a = array_fill(0,2,false);
foreach($a as $k=>$v)
  $a[$k] = new T();
print_r($a);
$a[0]->add('foo');
print_r($a);
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 23:01:26 2024 UTC