Як зробити глибоку копію об'єкта DateTime?


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

Тепер $date1і $date2містять ту саму дату - три роки відтепер. Я хотів би створити два окремих дати, один, який розбирається з рядка і один з трьома роками, доданий до нього. В даний час я зламав це так:

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

але це здається жахливим злом. Чи існує "правильний" спосіб глибокої копіювання об'єкта DateTime?

Відповіді:


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

Оновлення:

Якщо ви хочете скопіювати, а не посилатися на існуючий DT-об'єкт, використовуйте clone, не =.

$a = clone $b;


12
Я використовував новий DateTime у прикладі, щоб продемонструвати точку, але наразі припустимо, що DateTime повертається з якогось непрозорого API, що я не можу просто передзвонити знову. Наприклад, у мене є функція, яка обробляє замовлення, яка повертає DateTime, коли клієнт може наступне зробити замовлення. Виклик функції створення копії створює побічні ефекти, які я не хочу.
Біллі ONeal

Я його ще не перевіряв, але на php.net зазначається, що це лише на користь для PHP 5.3 і вище.
hugo der hungrige

@hugo: Так, для класу DateTime потрібен PHP 5.3.
Біллі ONeal

11
Тільки коли я подумав, що я зрозумів PHP, я дізнаюся про нового оператора.
kr094

Довелося це зробити, щоб скопіювати існуючий об'єкт Carbon в іншу змінну. Це спрацювало.
racl101

111

Клоніруйте дату оператором клонування :

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

Клони за замовчуванням дрібні, але досить глибокі для DateTime. У власних об'єктах ви можете визначити __clone()магічний метод для клонування властивостей (тобто дочірніх об’єктів), які мають сенс клонувати, коли змінюється батьківський об'єкт.

(Я не впевнений, чому документація вважає хорошим прикладом необхідності клонування об'єкта GTK. Хто використовує GTK в PHP?)


1
Дякую за відповідь, але як ви знаєте, що це досить глибоко для DateTime? Які атрибути залишаються посиланнями, а які копіюються за значенням? Наприклад, я можу змінити час і часовий пояс, і це не вплине на клон?
Девід

1
@David: Я знаю, що це досить глибоко для DateTime, тому що я спробував це, і він працював на мене. Я не намагався змінити часовий пояс або будь-які інші речі, просто основний час та дату.
rjmunro

3
Використовуючи Xdebug, var_dump ($ date1) повідомляє, що він містить рядок 'date' =>, 'timezone_type' => рядок int & 'timezone' =>. Оскільки, здається, немає масивів чи об'єктів, а лише основні скаляри, дрібний клон повинен бути добре.
CJ Dennis

46

PHP 5.5.0 введено DateTimeImmutable . додавання та змінення методів цього класу повернення нових об'єктів.

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

4
Зауважте, що, на жаль, ви не можете просто поміняти DateTimeна DateTimeImmutable. Принаймні IntlDateFormatter::formatObject, це не любить незмінних (повертається falseзамість відформатованого рядка).
користувач276648

1
ой! Я якось ніколи не знав, що це існує, хоча я давно мріяв про це. і весь шлях назад в 5,5 ...
Бен

2
Як і якийсь ноб, я щойно стикався з об'єктом, орієнтованим на об'єкт, змінюючи мій DateTimeоб’єкт у циклі for: D Це чудово вирішило його ...
Wilt

3
@ user276648 Ця помилка тепер виправлена ​​у php 7.1.5 php.net/ChangeLog-7.php#7.1.5
jontro

11

TLDR:

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

(Неглибока копія є простою - глибоке копіювання DateTime не має сенсу )

Просто як це :)

Пояснення "php створити об'єкт дати з іншого часу":

  1. cloneКлючові слова роблять регулярну неглибоку копію - enaugh для цього випадку (чому => дивись нижче)
  2. Обертаючи його за допомогою ()оцінює вираз, повертаючи новостворений об’єктclone
  3. ->modify() Тому викликається і модифікує новий об'єкт
  4. DateTime::modify(...) Документи:

    Повертає об'єкт DateTime для ланцюжка методів або FALSE при відмові.

  5. $date2тепер містить новостворений та модифікований клон / копію, $date1залишаючись незмінним

Чому ви не повинні глибокої копії тут:

Глибока копія / клонування необхідна лише тоді, коли вам потрібно скопіювати цілі властивостей, які є посиланнями , але це:

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

так що немає ніяких посилань, тільки прості типів => немає необхідності глибокої копії.


1

Ви повинні змінити DateTimeToDateTimeImmutable

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

то ви можете зателефонувати будь-якому методу, DateTimeне турбуючись про його зміну


Це справді відповідь на інше питання.
Біллі ONeal

@BillyONeal я міг би не пояснив повністю , як, але це рішення цієї проблеми в якості джерела цієї проблеми полягає в тому , як виклик методу addна date2зміни значення , date1і немає ніякого способу , щоб скопіювати значення DateTimeзмінної , якщо не маютьDateTimeImmutable
Hossein Shahdoost
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.