print_r() 向 DateTime 对象添加属性 [重复]
Posted
技术标签:
【中文标题】print_r() 向 DateTime 对象添加属性 [重复]【英文标题】:print_r() adds properties to DateTime objects [duplicate] 【发布时间】:2013-06-08 14:19:41 【问题描述】:考虑以下代码示例:
$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
类的一部分。
【问题讨论】:
@Jessica 同时运行这两个代码块。为第二个而不是第一个生成警告。唯一的区别是print_r
在第二个中被注释掉了
多哈。我当时想,这似乎很明显。 :-P 我明白你的意思,我运行了代码 - 不知道。
我的猜测是,这是某种内部私有/受保护的属性,在转储时被放入对象/公开。
这不是错误。阅读手册,您会发现没有公共属性“日期”。
@vascowhite 不过,这不是问题所在;这就是为什么它出现在print_r()
之后;授予,它可能首先是由于一个错误:)
【参考方案1】:
DateTime
中没有 date
属性;这就是为什么你会收到(Undefined property: DateTime::$date).
print_r()
对对象执行一些introspection 以显示其内容;这会导致对象神奇地创建::date
属性。虽然这没有记录,所以将来使用它可能会破坏您的代码。
你需要像$m_oDate->format('m-d-Y');
这样的东西。
【讨论】:
为什么投反对票?这是绝对正确的。虽然它没有解释为什么在包含print_r()
时不会看到错误
@DaveRandom 它没有回答问题。
print_r 打印对象,echo 需要一个字符串才有意义。
@DaveRandom:不是我的 dv,但即使它是真的,它也完全没有抓住问题的重点,所以当被判断为答案时它是非常糟糕的(最近的编辑证实了这一点)。我们不会仅判断答案的技术价值。
@Jon 我知道你来自哪里,但在某种程度上它绝对回答了这个问题:DateTime
的接口在 PHP 手册中定义,因此在主题 不包括->date
属性。所以问题实际上是“为什么我在尝试访问不属于接口的属性时会出错”,而用这种方式表达的答案是“因为它不是接口的一部分”。我确实理解它并不能完全回答所问问题的观点,但我会反驳 OP 提出了错误的问题 ;-)【参考方案2】:
这在 PHP 中是 reported as Bug #49382。
在 PHP 5.3 中,添加了内部功能以允许 print_r()
显示 DateTime
实例所持有的底层时间戳值的详细信息,以帮助调试。此更改的副作用是,当对象转储为文本时,这些幻像公共属性将添加到实例中。
使用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
持有的字符串类型——即上面代码示例中获取时区信息的三种方法之一。为了完整起见,它的可能值为defined,方式如下:
【讨论】:
这不是错误 - 这是一项功能! 这不是错误。阅读manual,您会看到没有公共属性“日期”。 这是一个错误。 @Danack 在他的回答中解释了这一点。 @vascowhite:你还没有理解这个问题。 现在您可以将其用作功能:$x = new DateTime(); ob_start(); print_r($x); ob_end_clean(); echo $x->date;
【参考方案3】:
发生了一些魔法,但很简单。
DateTime 类没有您要访问的公共变量“日期”。但是,作为 PHP 工作方式的副作用,当您在该类上调用 print_r 或 var_dump 时会创建一个变量。
魔法发生后,“日期”可用,但不应该。您应该只使用 getTimestamp 函数来使您的代码可靠地工作。
【讨论】:
谢谢。这是最能回答我的问题的回答(就我的 - 原始 - 象征性问题而言)【参考方案4】:为了它的乐趣,这就是你如何使它工作,使用Reflection
:
$m_oDate = new DateTime('NOW');
$o = new ReflectionObject($m_oDate);
$p = $o->getProperty('date');
echo $p->getValue($m_oDate);
Source
【讨论】:
【参考方案5】:您应该使用DateTime::format
或DateTimeImmutable::format
视情况而定
$m_oDate = new DateTime('NOW');
echo $m_oDate->format("r");
【讨论】:
【参考方案6】:问题lies here:
static HashTable *date_object_get_properties(zval *object TSRMLS_DC)
// ...
zend_hash_update(props, "date", 5, &zv, sizeof(zval), NULL);
// ...
当进行任何数据转储(print_r
、var_dump
、var_export
)时,将调用函数date_object_get_properties
。哈希表更新了数据表示,不幸的是,这是公开的。
【讨论】:
【参考方案7】:考虑以下代码示例:
$m_oDate = new DateTime('2013-06-12 15:54:25');
some_func($m_oDate);
echo $m_oDate->'ROXXOR_IS_BACK!!';
与您最明显的区别是调用 some_func
而不是 print_r
函数。期望可能会有所不同,因为您知道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 3 中引入 PHP 中的对象的时间有关:
在 PHP 3.0 的源代码树中引入类时,它们被添加为访问集合的语法糖。 PHP 已经有了关联数组集合的概念,而新的 critter 只不过是一种访问它们的简洁的新方法。然而,随着时间的推移,事实证明,这种新语法对 PHP 的影响比最初预期的要深远得多。
-- Zeev Suraski about the standard object 自 PHP 3 (archived copy) - 通过 Why return object instead of array?
这也是为什么在 PHP 中完全常见函数可以添加之前在类中未定义的成员变量的简单解释。这些总是公开的。
因此,当您对某些 对象 是否具有属性进行假设时,请查看它的来源。它不能是类的一部分,但可能是以后添加的。
请记住以下几点:
不要在生产代码中使用
print_r
和var_dump
。
【讨论】:
而且它还表明使用 PHP 中的 any 对象完全可以轻松实现。 不是这样:codepad.viper-7.com/vwm2qp @PLB: codepad.viper-7.com/vwm2qp - 不太好。那个网站挂了。但肯定我的那句话有点拗口。 我的意思是定义__set
方法和自定义实现的对象。例如:3v4l.org/7EUhl
@PLB:您的示例不完整;)。即使对于这些对象, 也可以设置变量属性。请参阅此代码:3v4l.org/itpSn。
不,它并不完整。该示例背后的士气是对象可能具有这样的 __get
和/或 __set
实现,无法像那样添加公共属性,这意味着您所说的对于 any 对象是正确的,但是这些。这类实现确实很少见,但它们仍然存在。以上是关于print_r() 向 DateTime 对象添加属性 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
pandas使用to_datetime函数将时间字符串转化为时间对象使用dt.tz_localize为转化后的时间对象添加时区信息(timezone)