请考虑以下代码示例:
$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
类的一部分。
答案 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_properties
(print_r
,var_dump
,var_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)以来
这也是为什么在PHP中完全通用的简单解释,函数可以添加之前未在类中定义的成员变量。这些都是公开的。
因此,当您对某些具有属性的对象进行假设时,请查看其来源。它不能是课程的一部分,但可能会在以后添加。
请记住以下几点:
请勿在生产代码中使用
print_r
和var_dump
。
答案 5 :(得分:1)
为了方便起见,使用Reflection
:
$m_oDate = new DateTime('NOW');
$o = new ReflectionObject($m_oDate);
$p = $o->getProperty('date');
echo $p->getValue($m_oDate);
答案 6 :(得分:0)
您应该使用DateTime::format
或DateTimeImmutable::format
,视情况而定
$m_oDate = new DateTime('NOW');
echo $m_oDate->format("r");