print_r () добавляет свойства объектам DateTime

Рассмотрим следующий пример кода:

$m_oDate = new DateTime('2013-06-12 15:54:25'); print_r($m_oDate); echo $m_oDate->date; 

Начиная с PHP 5.3, это производит (что-то вроде) следующий вывод:

 DateTime Object ( [date] => 2013-06-12 15:54:25 [timezone_type] => 3 [timezone] => Europe/Amsterdam ) 2013-06-12 15:54:25 

Однако следующий код:

 $m_oDate = new DateTime('2013-06-12 15:54:25'); echo $m_oDate->date; 

… просто испускает ошибку:

 Notice: Undefined property: DateTime::$date in ... 

Почему print_r() «добавляет» эти свойства к объекту? Обратите внимание, что они не определены как часть класса DateTime на странице руководства .

Существует какая-то магия, но это довольно просто.

Класс DateTime не имеет открытой переменной «date», к которой вы хотите получить доступ. Однако, как побочный эффект работы PHP, существует переменная, созданная при вызове print_r или var_dump в этом классе.

После этого волшебства появляется «дата», но этого не должно быть. Вы должны просто использовать функцию getTimestamp, чтобы обеспечить надежную работу вашего кода.

Об этом сообщается в Bug # 49382 в PHP.

В PHP 5.3 была добавлена ​​внутренняя функциональность, позволяющая print_r() показывать детали базового значения временной метки, хранящиеся в экземпляре DateTime , для оказания помощи при отладке. Побочным эффектом этого изменения является то, что когда объект сбрасывается в текст, эти фантомные публичные свойства добавляются в экземпляр.

Тот же эффект может быть достигнут путем использования отражения для доступа к этим свойствам, и если вам нужно получить доступ к свойствам, то использование рефлексии будет способом, поэтому вы не вызываете ошибку.

Однако следует отметить, что вы не должны действительно использовать эти свойства – поскольку они не определены как члены объекта, нет гарантии, что они будут продолжать переносить одни и те же данные (или даже существуют) в будущих версиях PHP. Если вам нужно получить доступ к информации, используйте следующие методы, определенные как часть API, вместо этого:

 // $obj->date $obj->format('Ymd H:i:s'); // $obj->timezone $obj->getTimezone()->getName(); // or... $obj->getTimezone()->getOffset(); // or... $obj->getTimezone()->listAbbreviations(); // returns an array, so may need // further processing to be of use 

NB: свойство timezone_type недоступно через PHP API. Это внутреннее значение и не полезно в userland, так как оно описывает тип строки, которую занимает timezone шкал, когда объект сбрасывается, т. Е. Один из трех способов получения информации о часовом поясе в примере кода выше. Для полноты его возможные значения определяются следующим образом:

 Значение |  Тип |  Эквивалент
 ------ + ----------------------- + ------------------- ---------------
   1 |  смещение по времени |  DateTimeZone :: getOffset ()
   2 |  Сокращение времениZone |  DateTimeZone :: listAbbreviations ()
   3 |  Идентификатор TimeZone |  DateTimeZone :: GetName ()

В DateTime нет свойства date ; вот почему вы получаете (Undefined property: DateTime::$date).

print_r() выполняет некоторую интроспекцию объекта для отображения его содержимого; это заставляет объект магически создать свойство ::date . Это не документировано, поэтому использование этого может привести к нарушению вашего кода в будущем.

Вам нужно что-то вроде $m_oDate->format('md-Y'); вместо.

Проблема здесь :

 static HashTable *date_object_get_properties(zval *object TSRMLS_DC) { // ... zend_hash_update(props, "date", 5, &zv, sizeof(zval), NULL); // ... 

Функция date_object_get_properties вызывается, когда производится сброс данных ( print_r , var_dump , var_export ). Хэш-таблица обновляется для данных, которые, к сожалению, становятся общедоступными.

Рассмотрим следующий пример кода:

 $m_oDate = new DateTime('2013-06-12 15:54:25'); some_func($m_oDate); echo $m_oDate->{'ROXXOR_IS_BACK!!'}; 

Самое очевидное отличие от вас заключается в том, что вместо функции print_r some_func другая функция some_func . Ожидания могут отличаться, потому что вы знаете print_r но вы не знаете some_func но это только для того, чтобы обострить ваши чувства. Подождите немного, пока я не покажу определение этой функции.

Второе отличие – это имя свойства, которое получает эхо. Здесь я выбрал имя, которое действительно исключительное: {'ROXXOR_IS_BACK!!'} , снова для того, чтобы обострить ваши чувства.

Это имя, что безумное, что должно быть очевидно, не является частью DateTime хотя при выполнении приведенного выше примера совершенно ясно, что это свойство roxxor должно существовать . Выход программы:

 PHP never lets you down. 

Так почему? Да, вы наверняка уже знаете, как это работает. Функция some_func() должна добавить его. Итак, давайте рассмотрим определение функций:

 function some_func($m_oDate) { $m_oDate->{'ROXXOR_IS_BACK!!'} = 'PHP never lets you down.'; } 

Да, теперь ясно видно, что эта функция добавила свойство к объекту. И это также показывает, что это вполне возможно с любым объектом в PHP.

Сравните с массивом в PHP, вы также можете добавить новые ключи, когда захотите.

Этот пример не был выбран из ничего, потому что именно здесь возникают объекты в PHP: они всего лишь синтаксический сахар вокруг массивов, и это связано с тем, что объекты в PHP были введены на PHP 3:

В то время, когда классы были введены в исходное дерево того, что должно было стать PHP 3.0, они были добавлены в качестве синтаксического сахара для доступа к коллекциям. У PHP уже было понятие ассоциативных коллекций массивов, и новые твари были не чем иным, как опрятным новым способом доступа к ним. Однако, как показало время, этот новый синтаксис оказался гораздо более значительным для PHP, чем первоначально предполагалось.

Zeev Suraski о стандартном объекте с PHP 3 ( архивная копия ) – через Почему вернуть объект вместо массива?

Это также простое объяснение, почему это полностью распространено в PHP, функции могут добавлять переменные-члены, которые ранее не были определены в классе. Это всегда публично.

Поэтому, когда вы делаете предположения о каком-либо объекте, обладающем свойством или нет, посмотрите, откуда он. Он не должен быть частью класса, но может быть добавлен позже.

И помните следующее:

Не используйте print_r и var_dump в производственном коде.

Для удовольствия это так, как вы можете заставить его работать, используя Reflection :

 $m_oDate = new DateTime('NOW'); $o = new ReflectionObject($m_oDate); $p = $o->getProperty('date'); echo $p->getValue($m_oDate); 

Источник

Вы должны использовать DateTime::format или DateTimeImmutable::format как это может быть

 $m_oDate = new DateTime('NOW'); echo $m_oDate->format("r");