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 класс страница руководства.

7 ответов


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

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

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


это сообщается как ошибка #49382 в PHP.

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

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

однако следует отметить, что вы не должны использовать эти свойства - поскольку они не определены как члены объекта, нет никакой гарантии, что они будут продолжать нести те же данные (или даже существовать) в будущих версиях 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

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

Value | Type                  | Userland equivalent
------+-----------------------+----------------------------------
  1   | time offset           | DateTimeZone::getOffset()
  2   | TimeZone abbreviation | DateTimeZone::listAbbreviations()
  3   | TimeZone identifier   | DateTimeZone::getName()

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

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

нужно что-то вроде $m_oDate->format('m-d-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 называется. Ожидания могут отличаться, потому что вы знаете print_r но вы не знаете some_func но это только для того, чтобы обострить ваши чувства. Давайте подождем, пока я покажу определение этой функции.

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

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

PHP never lets you down.

так почему? Да, ты уже знаешь, как это работает. The 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, чем изначально предназначенный.

-- Зеев Сураски о стандарте-объект начиная с 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");