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
на странице .
Ответы
Ответ 1
Существует какая-то магия, но она довольно проста.
Класс DateTime не имеет общедоступной переменной 'date', к которой вы хотите получить доступ. Однако, как побочный эффект работы PHP, существует переменная, созданная при вызове print_r или var_dump в этом классе.
После этого волшебства появляется "дата", но этого не должно быть. Вы должны просто использовать функцию getTimestamp, чтобы ваш код работал надежно.
Ответ 2
Это было как ошибка # 49382 в PHP.
В PHP 5.3 добавлена внутренняя функциональность, чтобы позволить print_r()
отображать сведения о базовом значении временной метки, хранящейся в экземпляре DateTime
, чтобы помочь в отладке. Побочным эффектом этого изменения является то, что когда объект сбрасывается в текст, эти phantom общедоступные свойства добавляются в экземпляр.
Тот же эффект может быть достигнут с помощью reflection для доступа к этим свойствам, и если вам нужно получить доступ к свойствам, то использование отражения будет быть способ пойти, поэтому вы не вызываете ошибку.
Однако следует отметить, что вы не должны действительно использовать эти свойства - поскольку они не определены как члены объекта, нет гарантии, что они будут продолжать переносить одни и те же данные (или даже существуют) в будущем PHP версии. Если вам нужно получить доступ к информации, используйте следующие методы, определенные как часть API, вместо этого:
// $obj->date
$obj->format('Y-m-d 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
Примечание. Свойство timezone_type
недоступно через PHP API. Это внутреннее значение и не полезно в пользовательской области, поскольку оно описывает тип строки, которая timezone
выполняется при удалении объекта, т.е. Один из трех способов получения информации о часовом поясе в примере кода выше. Для полноты его возможные значения определены следующим образом:
<Предварительно > Значение | Тип | Эквивалент
------ + ----------------------- + ------------------- --------------- 1 | смещение по времени | DateTimeZone:: getOffset()2 | Сокращение времениZone | DateTimeZone:: listAbbreviations()3 | Идентификатор TimeZone | DateTimeZone:: getName()
Ответ 3
Нет свойства date
в DateTime
; почему вы получаете (Undefined property: DateTime::$date).
print_r()
выполняет интроспекцию объекта для отображения его содержимого; это заставляет объект магически создавать свойство ::date
. Это не документировано, поэтому использование этого может привести к повреждению вашего кода в будущем.
Вместо этого вам нужно что-то вроде $m_oDate->format('m-d-Y');
.
Ответ 4
Проблема лежит здесь:
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
). Хэш-таблица обновляется для данных, которые, к сожалению, становятся общедоступными.
Ответ 5
Рассмотрим следующий пример кода:
$m_oDate = new DateTime('2013-06-12 15:54:25');
some_func($m_oDate);
echo $m_oDate->{'ROXXOR_IS_BACK!!'};
Наиболее очевидным отличием от вашего является то, что вместо функции print_r
вызывается другая 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
в производственном коде.
Ответ 6
Для удовольствия от этого вы можете заставить его работать, используя Reflection
:
$m_oDate = new DateTime('NOW');
$o = new ReflectionObject($m_oDate);
$p = $o->getProperty('date');
echo $p->getValue($m_oDate);
Источник
Ответ 7
Вы должны использовать DateTime::format
или DateTimeImmutable::format
, в зависимости от ситуации
$m_oDate = new DateTime('NOW');
echo $m_oDate->format("r");