4

I'm new to PHP. The following bug(?) took me 891723498 hours to locate in my code. Can someone explain to me what is causing this, and maybe a way to fix it? Right now I'm just leaving the json_encode() call in.

This is a distilled version of my code. There may be other functions than json_encode() that have the same effect, I don't know.

This is a straight copy-paste from my repl (using the Boris php repl -- https://github.com/borisrepl/boris).

./bin/boris
[1] boris> function broken () {
[1]     *>   $timezone = new DateTimeZone("America/New_York");
[1]     *>   $datetime = new DateTime("now", $timezone);
[1]     *>   return date_parse($datetime->date);
[1]     *> }
// NULL
[2] boris>
[2]     *> function works () {
[2]     *>   $timezone = new DateTimeZone("America/New_York");
[2]     *>   $datetime = new DateTime("now", $timezone);
[2]     *>   json_encode($datetime);
[2]     *>   return date_parse($datetime->date);
[2]     *> }
// NULL
[3] boris> broken();
PHP Notice:  Undefined property: DateTime::$date in /home/sirrobert/Projects/sirrobert/archon/code/repl/boris/lib/Boris/EvalWorker.php(152) : eval()'d code on line 4
// array(
//   'year' => false,
//   'month' => false,
//   'day' => false,
//   'hour' => false,
//   'minute' => false,
//   'second' => false,
//   'fraction' => false,
//   'warning_count' => 0,
//   'warnings' => array(
//
//   ),
//   'error_count' => 1,
//   'errors' => array(
//     0 => 'Empty string'
//   ),
//   'is_localtime' => false
// )
[4] boris> works();
// array(
//   'year' => 2016,
//   'month' => 11,
//   'day' => 30,
//   'hour' => 16,
//   'minute' => 53,
//   'second' => 35,
//   'fraction' => 0.0,
//   'warning_count' => 0,
//   'warnings' => array(
//
//   ),
//   'error_count' => 0,
//   'errors' => array(
//
//   ),
//   'is_localtime' => false
// )
[5] boris>

Here's the same thing from the php -a repl with less helpful output.

php > function broken () {
php {   $timezone = new DateTimeZone("America/New_York");
php {   $datetime = new DateTime("now", $timezone);
php {   return date_parse($datetime->date);
php { }
php >
php > function works () {
php {   $timezone = new DateTimeZone("America/New_York");
php {   $datetime = new DateTime("now", $timezone);
php {   json_encode($datetime);
php {   return date_parse($datetime->date);
php { }
php >
php > broken()
php > ;
PHP Notice:  Undefined property: DateTime::$date in php shell code on line 4
php > works();
php >

Why in the world does the json_encode($datetime) "realize" the $datetime object?

My best guess is that either:

  1. Some kind of vivification is happening when the $datetime object is being used in json_encode() that isn't when it's being accessed for properties,

or

  1. I'm hitting some kind of race condition in parallelized internals code?
Sir Robert
  • 4,686
  • 7
  • 41
  • 57
  • The `[2] *> json_encode($datetime);` part does nothing*. And read here how to access a DateTime Object http://php.net/manual/en/book.datetime.php *you are doing nothing with the return value. – JOUM Nov 30 '16 at 22:13
  • 1
    If you change it to `return date_parse($datetime->format('Y-m-d H:i:s'));` it works – RiggsFolly Nov 30 '16 at 22:19
  • To me to does seem like the date property isn't defined until something internally is called, however, I'd suggest there are better interfaces to get the date output you require (you can trigger the same behavior with `print_r` or `var_dump` instead of `json_encode`), it's a bit of a Schrödinger class it seems. – Scuzzy Nov 30 '16 at 22:20
  • I have to admit I have never seen anyone using `$dt->date` directly before, it looks logical but just never seen it used directly – RiggsFolly Nov 30 '16 at 22:20
  • @Scuzzy `Schrödinger class` a.k.a. LazyLoader ;) – JOUM Nov 30 '16 at 22:28
  • @JOUM Thanks-- I know I'm doing nothing with the return value-- that's what I mean when I said "do a no-op". – Sir Robert Dec 01 '16 at 00:19
  • @RiggsFolly Maybe it's just a bias coming from other languages, but I figured if I already have a rendered version, why do more function calls? – Sir Robert Dec 01 '16 at 00:20
  • 1
    https://bugs.php.net/bug.php?id=49382 and http://stackoverflow.com/questions/14084222/ looks like it's been around for a while too. and – Scuzzy Dec 01 '16 at 01:51

1 Answers1

0

Ok, based on the comments and links provided, it looks like this is a known (but unprioritized) issue, per http://bugs.php.net/bug.php?id=49382 and Why can't I access DateTime->date in PHP's DateTime class? Is it a bug?

The issue appears to be lazy loading of the DateTime class, which isn't apparently correctly triggered through accessing the properties of the object directly.

The solution is apparently to do what I did (a no-op) or do specific string formatting, even if the format you want them in is the default ->date format.

Community
  • 1
  • 1
Sir Robert
  • 4,686
  • 7
  • 41
  • 57