SlimenTN
SlimenTN

Reputation: 3564

PHP: array values changes after for loop

I know the title looks weird but this is what just happened to me.
I have created a funtion that takes DateTime and integer and return array of dates, and this is my code:

public static function generateAfterDate(\DateTime $from, $number){
        $days = array();
        array_push($days, $from);
        for($i = 1; $i <= $number; $i++){
            $from = $from->modify('+1 day');
            $days[] = $from;
            var_dump($days[$i]->format('d/m/Y'));//---The first var_dump
        }
        foreach ($days as $day){
            var_dump($day->format('d/m/Y'));//--The second var_dump
        }
        die;
        return $days;
    }

generateAfterDate(new \DateTime(), 7);

As you can see I'm using the same array to var_dump data and I get two different results:
The first one gave me this:

string(10) "22/10/2017" string(10) "23/10/2017" string(10) "24/10/2017" string(10) "25/10/2017" string(10) "26/10/2017" string(10) "27/10/2017" string(10) "28/10/2017"

And the second one gave me this result:

string(10) "28/10/2017" string(10) "28/10/2017" string(10) "28/10/2017" string(10) "28/10/2017" string(10) "28/10/2017" string(10) "28/10/2017" string(10) "28/10/2017" string(10) "28/10/2017"

Can someone please explain this ?

Upvotes: 0

Views: 73

Answers (2)

Osama
Osama

Reputation: 3040

As I think that your first var_dump is the right one with your expected result the second one return only the last value because foreach loop create a copy of the array while you use the variable $day so it will always refer to the last one the right code is

 foreach ($days as $key=>$day){
        var_dump($days[$key]->format('d/m/Y'));//--The  second var_dump
     }

Upvotes: 1

rickdenhaan
rickdenhaan

Reputation: 11318

This happens because variables containing objects (like a DateTime object) don't actually contain the object, but a reference to the memory address that holds that object.

So by putting the $from variable into your $days array, you are not putting a copy of your DateTime object with its current state into the array, but you are putting a copy of the memory address reference into the array. Therefore, modifying the DateTime pointed to by the $from reference will also modify the same DateTime referenced by every single entry in your $days array.

What you need to do instead is duplicate the DateTime object and its state to a new DateTime instance when you add it to the array. Fortunately, PHP has a simple way to do just that: clone

array_push($days, clone $from);
for($i = 1; $i <= $number; $i++){
    $from = $from->modify('+1 day');
    $days[] = clone $from;
    var_dump($days[$i]->format('d/m/Y'));//---The first var_dump
}

Now your $days array will still contain references to a memory address, but it will be a different memory address containing a unique instance of a DateTime object for each entry.

Upvotes: 2

Related Questions