Рассмотрим следующий пример кода:
$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");