print_r()向DateTime对象添加属性

时间:2013-06-12 12:53:23

标签: php debugging datetime php-internals

请考虑以下代码示例:

$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()“将”这些属性添加到对象中?请注意,它们未定义为manual page上的DateTime类的一部分。

7 个答案:

答案 0 :(得分:14)

这在PHP中已经reported as Bug #49382

在PHP 5.3中,添加了内部功能以允许print_r()显示DateTime实例所持有的基础时间戳值的详细信息,以协助调试。此更改的副作用是,当将对象转储到文本时,会将这些幻像公共属性添加到实例中。

使用reflection访问这些属性可以实现相同的效果,如果您需要访问属性,那么使用反射将是最佳选择,因此您不会引发错误。

但是,应该注意的是,你不应该真正使用这些属性 - 因为它们没有被定义为对象的成员,所以不能保证它们将来会继续携带相同的数据(甚至存在)版本。如果您需要访问该信息,请使用以下方法(定义为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

注意:无法通过PHP API访问timezone_type属性。它是一个内部值,在userland中没用,因为它描述了转换对象时timezone保持的字符串类型 - 即上述代码示例中获取时区信息的三种方法之一。为完整起见,其可能的值为defined,方法如下:

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

答案 1 :(得分:9)

DateTime中没有date属性;这就是你得到(Undefined property: DateTime::$date).

的原因

print_r()对对象执行一些introspection以显示其内容;这会导致对象神奇地创建::date属性。但是没有记录,因此使用它可能会在将来破坏您的代码。

您需要$m_oDate->format('m-d-Y');之类的内容。

答案 2 :(得分:9)

有一些神奇的事情发生但很简单。

班级DateTime没有您要访问的公共变量“日期”。但是,作为PHP工作方式的副作用,在该类上调用print_r或var_dump时会创建一个变量。

在那之后,魔法发生'日期'可用,但它不应该。您应该只使用getTimestamp函数来使代码可靠地运行。

答案 3 :(得分:5)

问题lies here

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

在进行任何数据转储时调用函数date_object_get_propertiesprint_rvar_dumpvar_export)。哈希表针对表示的数据进行了更新,不幸的是,这是公开的。

答案 4 :(得分:2)

考虑以下代码示例:

$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!!'},再次提升你的感官。

这个名字是 crazy 必须显而易见的不是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的影响远远超出了最初的预期。

     自PHP 3(Zeev Suraski about the standard object)以来

- archived copy - 来自Why return object instead of array?

这也是为什么在PHP中完全通用的简单解释,函数可以添加之前未在类中定义的成员变量。这些都是公开的。

因此,当您对某些具有属性的对象进行假设时,请查看其来源。它不能是课程的一部分,但可能会在以后添加。

请记住以下几点:

  

请勿在生产代码中使用print_rvar_dump

答案 5 :(得分:1)

为了方便起见,使用Reflection

可以实现这一点
$m_oDate = new DateTime('NOW');
$o = new ReflectionObject($m_oDate);
$p = $o->getProperty('date');
echo $p->getValue($m_oDate);

Source

答案 6 :(得分:0)

您应该使用DateTime::formatDateTimeImmutable::format,视情况而定

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