php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79041 PHP 7.4 changed foreach behavior for DateTime object
Submitted: 2019-12-28 11:58 UTC Modified: 2022-07-22 16:20 UTC
Votes:8
Avg. Score:4.5 ± 0.7
Reproduced:7 of 7 (100.0%)
Same Version:5 (71.4%)
Same OS:2 (28.6%)
From: robert at korulczyk dot pl Assigned: derick (profile)
Status: Wont fix Package: Date/time related
PHP Version: 7.4.1 OS:
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: robert at korulczyk dot pl
New email:
PHP Version: OS:

 

 [2019-12-28 11:58 UTC] robert at korulczyk dot pl
Description:
------------
In PHP 7.4 behavior of `foreach (new DateTime() as $property => $value)` has changed. Prior to 7.4 foreach iterates through virtual properties of DateTime object. Since 7.4 it is treated as empty array, which makes it incosistent with `json_encode()` and `(array)` cast. Cast to array was already fixed in https://bugs.php.net/bug.php?id=78383

https://3v4l.org/h99LLn

Context - foreach approach is used in Json helper in Yii 2:
https://github.com/yiisoft/yii2/issues/17760
https://github.com/yiisoft/yii2/blob/a636ff916ac3a06756f37c0dbfb55994394a6a55/framework/helpers/BaseJson.php#L160-L166

Test script:
---------------
$date = new DateTime('2019-12-24');
$properties = [];
foreach ($date as $k => $v) {
    $properties[$k] = $v;
}
var_dump($date);
var_dump((array) $date);
var_dump($properties);
echo json_encode($date), "\n";
echo json_encode((array) $date), "\n";
echo json_encode($properties), "\n";

Expected result:
----------------
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2019-12-24 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(16) "Europe/Amsterdam"
}
array(3) {
  ["date"]=>
  string(26) "2019-12-24 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(16) "Europe/Amsterdam"
}
array(3) {
  ["date"]=>
  string(26) "2019-12-24 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(16) "Europe/Amsterdam"
}
{"date":"2019-12-24 00:00:00.000000","timezone_type":3,"timezone":"Europe\/Amsterdam"}
{"date":"2019-12-24 00:00:00.000000","timezone_type":3,"timezone":"Europe\/Amsterdam"}
{"date":"2019-12-24 00:00:00.000000","timezone_type":3,"timezone":"Europe\/Amsterdam"}


Actual result:
--------------
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2019-12-24 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(16) "Europe/Amsterdam"
}
array(3) {
  ["date"]=>
  string(26) "2019-12-24 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(16) "Europe/Amsterdam"
}
array(0) {
}
{"date":"2019-12-24 00:00:00.000000","timezone_type":3,"timezone":"Europe\/Amsterdam"}
{"date":"2019-12-24 00:00:00.000000","timezone_type":3,"timezone":"Europe\/Amsterdam"}
[]

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-12-30 16:15 UTC] nikic@php.net
Not willing to provide BC for this. DateTime doesn't have virtual properties -- it has a debug representation (think __debugInfo()).

To account for that particular use-case it would be nice if DateTime implemented JsonSerializable rather than doing the same via an internal side-channel. Unfortunately that is a bit problematic as json is an optional extension.
 [2020-01-01 21:28 UTC] robert at korulczyk dot pl
Any plans to fix this mess in PHP 8? Current behavior is really confusing, especially with BC hack for `(array)` cast.
 [2020-01-10 20:23 UTC] camporter1 at gmail dot com
Would it be possible to list this in the BC section of the 7.3 to 7.4 migration docs?
 [2020-01-20 17:09 UTC] girgias@php.net
-Assigned To: +Assigned To: derick
 [2020-01-20 17:09 UTC] girgias@php.net
Not sure if this shouldn't be a feature request, assigning to Derick as he is the maintainer of the Date extension.
 [2021-02-09 12:53 UTC] drodriguez816 at gmail dot com
Also there is a problem with reflection.
Reflection is not returning the datetime properties. So $props array will remain empty..

$date = new DateTime();
$reflection = new ReflectionObject($date);
$props = [];

foreach ($reflection->getProperties() as $p) {
    $props[] = $p->getName();
}

var_dump($props);
 [2022-07-22 16:20 UTC] derick@php.net
-Status: Assigned +Status: Wont fix
 [2022-07-22 16:20 UTC] derick@php.net
I'm going to mark this as "won't fix". DateTime(Immutable) does not have real properties, and the once that show up with serialize/json_encode, and (array), are there to handle this specific case.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 07:01:29 2024 UTC