php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71454 foreach last element is copy of penultimate, with array of DateIntervals
Submitted: 2016-01-26 11:51 UTC Modified: 2016-01-26 13:59 UTC
From: qdinar at gmail dot com Assigned:
Status: Not a bug Package: Date/time related
PHP Version: Irrelevant OS: windows 10
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: qdinar at gmail dot com
New email:
PHP Version: OS:

 

 [2016-01-26 11:51 UTC] qdinar at gmail dot com
Description:
------------
foreach through array of DateIntervals gives penultimate element instead of last element

Test script:
---------------
$intervals=array(1,2,3,4,5,6);
foreach($intervals as &$interv){
	$interv = new DateInterval('PT'.$interv.'M');	
}
$time = new DateTime('6:20');
foreach($intervals as $interv){
	echo ','.$interv->format('%i');
}


Expected result:
----------------
,1,2,3,4,5,6

Actual result:
--------------
,1,2,3,4,5,5

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-01-26 11:54 UTC] qdinar at gmail dot com
i have found a quick fix / workaround for this bug: use foreach($intervals as &$interv) (ie &$interv also in second foreach).
 [2016-01-26 13:59 UTC] rasmus@php.net
-Status: Open +Status: Not a bug
 [2016-01-26 13:59 UTC] rasmus@php.net
This is completely expected. If you unroll your loops you can see why. eg.

$interv = & $intervals[0];
$interv = & $intervals[1];
...
$interv = & $intervals[6];

Now you are at the end of your first loop and as you can see $interv is a reference to $intervals[6]; So at this point if you were to do:

$interv = 123;

it would be equivalent to doing:

$intervals[6] = 123;

So now when we unroll your 2nd loop you are doing:

$interv = $intervals[0];
$interv = $intervals[1];
...
$interv = $intervals[6];

which since $interv is a reference to $intervals[6] is actually doing:

$intervals[6] = $intervals[0];
$intervals[6] = $intervals[1];
...
$intervals[6] = $intervals[5]; // which is 5, of course
$intervals[6] = $intervals[6]; // still 5

It has to work this way because a loop has to be equivalent to its unrolled version. If you want to avoid side-effects like that, unset($interv) before the second loop. This is documented on http://php.net/foreach
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Wed Mar 12 07:01:32 2025 UTC