Php 如何深度复制DateTime对象?
现在Php 如何深度复制DateTime对象?,php,datetime,Php,Datetime,现在$date1和$date2包含相同的日期——三年后。我想创建两个单独的日期时间,一个是从字符串中解析出来的,另一个是添加了三年的。目前我已经把它砍成这样: $date1 = $date2 = new DateTime(); $date2->add(new DateInterval('P3Y')); 但这似乎是一个可怕的黑客行为。是否有一种“正确”的方法来深度复制DateTime对象 $date2 = new DateTime($date1->format(DateTime::
$date1
和$date2
包含相同的日期——三年后。我想创建两个单独的日期时间,一个是从字符串中解析出来的,另一个是添加了三年的。目前我已经把它砍成这样:
$date1 = $date2 = new DateTime();
$date2->add(new DateInterval('P3Y'));
但这似乎是一个可怕的黑客行为。是否有一种“正确”的方法来深度复制DateTime对象
$date2 = new DateTime($date1->format(DateTime::ISO8601));
更新:
如果要复制而不是引用现有DT对象,请使用克隆
,而不是=
$a=克隆$b代码>使用操作员克隆日期:
$date1 = new DateTime();
$date2 = new DateTime();
$date2->add(new DateInterval('P3Y'));
默认情况下,克隆是浅的,但深度足以容纳DateTime。在您自己的对象中,您可以定义\u clone()
魔术方法来克隆在父对象更改时有意义克隆的属性(即子对象)
(我不知道为什么文档认为需要克隆对象的一个好例子是GTK。谁在PHP中使用GTK?PHP5.5.0。此类的和方法返回新对象
$date1 = new DateTime();
$date2 = clone $date1;
$date2->add(new DateInterval('P3Y'));
您应该将DateTime
更改为DateTimeImmutable
$date1 = new DateTimeImmutable();
$date2 = $date1->add(new DateInterval('P3Y'));
然后,您可以调用DateTime
上的任何方法,而不必担心它的更改TLDR:
(浅拷贝是启用的-深度拷贝日期时间(当前)没有意义)
就这么简单:)
解释“php从另一个datetime创建datetime对象”:
对于这种情况,clone
关键字使常规的浅层复制-enaugh(为什么=>见下文)
用()
将其包装起来,通过克隆
计算返回新创建对象的表达式
->modify()
因此被调用并修改新对象
DateTime::修改(…)
docs:
返回方法链接的DateTime对象,失败时返回FALSE
$date2
现在包含新创建和修改的克隆/副本,而$date1
保持不变
为什么不需要在此处进行深度复制:
只有当您需要复制作为引用的属性的目标时,才需要进行深度复制/克隆,但是:
$date1 = new DateTime();
$date2 = (clone $date1)->modify('+3 years');
产出:
class TestDateTime extends DateTime{
public function test(){
//*this* way also outputs private variables if any...
var_dump( get_object_vars($this) );
}
}
$test = (new TestDateTime())->test();
因此没有引用,只有简单类型=>不需要深度复制。我在示例中使用了一个新的DateTime来演示这一点,但现在假设DateTime是从一些不透明的API返回的,我不能再调用它。例如,我有一个处理订单的函数,该函数返回一个日期时间,客户可以在该日期时间下一次下订单。调用函数创建副本会产生我不想要的副作用。实际上我还没有测试过它,但在php.net中提到,这只适用于PHP5.3及更高版本。@hugo:是的,DateTime类需要PHP5.3。正当我认为我掌握了PHP时,我学习了一个新的操作符。必须这样做才能将现有的Carbon对象复制到另一个变量。这很有效。谢谢你的回答,但是你怎么知道它足够深,适合DateTime?哪些属性保留引用,哪些属性按值复制?例如,我可以更改时间和时区,但这不会影响克隆?@David:我知道它对DateTime来说足够深,因为我尝试过,它对我有效。我没有尝试更改时区或其他任何东西,只是更改基本的时间和日期。使用Xdebug,var_dump($date1)报告它包含'date'=>string','timezone_type'=>int&'timezone'=>string。因为它似乎不包含任何数组或对象,只包含基本的标量,所以浅层克隆应该可以。这是最清晰的,大多数自文档化的答案,在代码库中遇到时非常有用,不会让同事感到困惑。请注意,不幸的是,您不能仅将日期时间
与日期时间不可变
交换。至少有IntlDateFormatter::formatObject
不喜欢不可变的(返回false
而不是格式化字符串)。哦!虽然我一直梦想着它,但不知何故,我从不知道它的存在。在5.5中,就像一些noob一样,我只是在for循环中修改了DateTime
对象,从而遇到了面向对象的陷阱:D这很好地解决了它…@user276648这个错误现在在PHP7.1.5中得到了修复,这确实是对另一个问题的回答。@BillyONeal我可能没有充分解释如何,但这是解决这个问题的方法,因为这个问题的根源是在date2
上调用方法add
如何更改date1
的值,并且除非您有DateTimeImmutable
我想看到克隆的源代码,否则无法复制DateTime
变量的值复制这是否意味着在PHP中也可以进行深度复制?我以为只有“克隆”来复制对象,而不仅仅是引用,对我来说这听起来像深度复制?@barell不确定我是否理解你的要求,但是clone
keyword does shallow copy=>复制简单的值,如int、strings等,如果在另一个对象上有引用,它只复制对该对象的引用。深度复制意味着为每个复制的对象创建一个新对象,等等-现在更清楚了吗?我不知道克隆对象部分中的对象引用。谢谢,知道这一点很有用。我希望我能早点看@巴雷尔:是的,这就是浅拷贝和深拷贝的区别:)很高兴我能帮忙!:-)
class TestDateTime extends DateTime{
public function test(){
//*this* way also outputs private variables if any...
var_dump( get_object_vars($this) );
}
}
$test = (new TestDateTime())->test();
array(3) {
["date"]=>
string(26) "2019-08-21 11:38:48.760390"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}