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"
    }