Wie kopiere ich ein DateTime-Objekt tief?

118
$date1 = $date2 = new DateTime();
$date2->add(new DateInterval('P3Y'));

Jetzt $date1und $date2mit demselben Datum - in drei Jahren. Ich möchte zwei separate Datumsangaben erstellen, eine, die aus einer Zeichenfolge analysiert wird, und eine, der drei Jahre hinzugefügt wurden. Derzeit habe ich es so gehackt:

$date2 =  new DateTime($date1->format(DateTime::ISO8601));

aber das scheint ein schrecklicher Hack zu sein. Gibt es eine "richtige" Möglichkeit, ein DateTime-Objekt tief zu kopieren?

Billy ONeal
quelle

Antworten:

171
$date1 = new DateTime();
$date2 = new DateTime();
$date2->add(new DateInterval('P3Y'));

Aktualisieren:

Wenn Sie ein vorhandenes DT-Objekt kopieren und nicht referenzieren möchten, verwenden Sie clonenicht =.

$a = clone $b;

Amy B.
quelle
12
Ich habe im Beispiel eine neue DateTime verwendet, um den Punkt zu demonstrieren, gehe aber vorerst davon aus, dass DateTime von einer undurchsichtigen API zurückgegeben wird, die ich nicht einfach erneut aufrufen kann. Zum Beispiel habe ich eine Funktion, die Bestellungen verarbeitet, die eine DateTime zurückgeben. Dann kann der Kunde das nächste Mal eine Bestellung aufgeben. Das Aufrufen der Funktion zum Erstellen einer Kopie führt zu Nebenwirkungen, die ich nicht möchte.
Billy ONeal
Ich habe es eigentlich nicht getestet, aber es wird auf php.net erwähnt, dass dies nur für PHP 5.3 und höher verfügbar ist.
Hugo der Hungrige
@hugo: Ja, für die DateTime-Klasse ist PHP 5.3 erforderlich.
Billy ONeal
11
Gerade als ich dachte, ich hätte ein Gespür für PHP, erfahre ich etwas über einen neuen Operator.
kr094
Musste dies tun, um ein vorhandenes Carbon-Objekt in eine andere Variable zu kopieren. Das hat funktioniert.
racl101
111

Klonen Sie das Datum mit dem Klonoperator :

$date1 = new DateTime();
$date2 = clone $date1;
$date2->add(new DateInterval('P3Y'));

Klone sind standardmäßig flach, aber tief genug für eine DateTime. In Ihren eigenen Objekten können Sie die __clone()magische Methode definieren , um die Eigenschaften (dh untergeordnete Objekte) zu klonen, deren Klonen sinnvoll ist, wenn sich das übergeordnete Objekt ändert.

(Ich bin mir nicht sicher, warum die Dokumentation GTK als gutes Beispiel für das Klonen eines Objekts ansieht. Wer verwendet GTK in PHP?)

rjmunro
quelle
1
Vielen Dank für die Antwort, aber woher wissen Sie, dass sie tief genug für DateTime ist? Welche Attribute bleiben Referenzen und welche werden nach Wert kopiert? Zum Beispiel kann ich die Zeit und die Zeitzone ändern und es wird den Klon nicht beeinflussen?
David
1
@ David: Ich weiß, dass es tief genug für DateTime ist, weil ich es ausprobiert habe und es für mich funktioniert hat. Ich habe nicht versucht, die Zeitzone oder andere Dinge zu ändern, nur die grundlegende Zeit und das Datum.
rjmunro
3
Unter Verwendung von Xdebug meldet var_dump ($ date1), dass es 'date' => string, 'timezone_type' => int & 'timezone' => string enthält. Da es keine Arrays oder Objekte zu enthalten scheint, sondern nur einfache Skalare, sollte ein flacher Klon in Ordnung sein.
CJ Dennis
46

PHP 5.5.0 führte DateTimeImmutable ein . Methoden zum Hinzufügen und Ändern dieser Klasse geben neue Objekte zurück.

$date1 = new DateTimeImmutable();
$date2 = $date1->add(new DateInterval('P3Y'));
Alexander Garden
quelle
4
Beachten Sie, dass Sie leider nicht einfach ein DateTimemit einem tauschen können DateTimeImmutable. Zumindest IntlDateFormatter::formatObjectmag das nicht unveränderlich (gibt falseanstelle der formatierten Zeichenfolge zurück).
user276648
1
Oh! Ich wusste irgendwie nie, dass es das gibt, obwohl ich lange davon geträumt habe. und den ganzen Weg zurück in 5.5 ...
Ben
2
Wie ein Noob bin ich gerade auf eine objektorientierte Falle gestoßen, indem ich mein DateTimeObjekt in einer for-Schleife geändert habe: D Das hat es gut gelöst ...
Wilt
3
@ user276648 Dieser Fehler wurde jetzt in PHP 7.1.5 behoben. php.net/ChangeLog-7.php#7.1.5
jontro
11

TLDR:

$date1 = new DateTime();
$date2 = (clone $date1)->modify('+3 years');

(Flache Kopie ist genug - Tiefes Kopieren DateTime macht (derzeit) keinen Sinn )

So einfach ist das :)

Erläuterung "php create datetime object from other datetime":

  1. Das cloneSchlüsselwort erstellt regelmäßig flache Kopien - genug für diesen Fall (warum => siehe unten)
  2. Wenn Sie es mit umschließen (), wird der Ausdruck ausgewertet, der das neu erstellte Objekt von zurückgibtclone
  3. ->modify() wird daher aufgerufen und modifiziert das neue Objekt
  4. DateTime::modify(...) docs:

    Gibt das DateTime-Objekt für die Methodenverkettung oder FALSE bei einem Fehler zurück.

  5. $date2Enthält jetzt den neu erstellten und geänderten Klon / die neu geänderte Kopie, $date1bleibt jedoch unverändert

Warum müssen Sie hier nicht tief kopieren:

Deep Copy / Clone ist nur erforderlich, wenn Sie Ziele von Eigenschaften kopieren müssen, die Referenzen sind , aber dies:

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();

Ausgänge:

array(3) {
  ["date"]=>
  string(26) "2019-08-21 11:38:48.760390"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}

Es gibt also keine Referenzen, nur einfache Typen => Sie müssen nicht tief kopieren.

jave.web
quelle
1

Sie sollten Ihre ändern DateTimezuDateTimeImmutable

// from date time
$date = \DateTimeImmutable::createFromMutable($mutableDate)

Dann können Sie eine beliebige Methode aufrufen, DateTimeohne sich Gedanken über die Änderung machen zu müssen

Hossein Shahdoost
quelle
Dies ist wirklich eine Antwort auf eine andere Frage.
Billy ONeal
@BillyONeal Ich habe möglicherweise nicht vollständig erklärt, wie, aber dies ist eine Lösung für dieses Problem, da die Ursache für dieses Problem darin besteht, dass das Aufrufen der Methode addbei date2den Wert von ändert date1und es keine Möglichkeit gibt, den Wert der DateTimeVariablen zu kopieren , es sei denn, Sie haben einDateTimeImmutable
Hossein Shahdoost