Quelle différence entre DateTime et DateTimeImmutable en PHP ?

Il existe en PHP deux classes pour gérer et manipuler nativement les dates: DateTime et DateTimeImmutable. Je me rends compte que de nombreux développeurs ne maitrisent pas la différence entre les deux notions. Ce billet est l’occasion de voir pourquoi et dans quel cas utiliser l’un ou l’autre.

Comme leur nom peut l’indiquer, la différence de fonctionnement est relative à la mutabilité de l’objet manipulé. Dans le cas de DateTime, l’instance de notre objet sera mutable. Cela signifie que la valeur de ce dernier peut être modifiée après sa création. Prenons le bout de code suivant qui va calculer une date prévisionnelle d’envoi d’une commande:

function getExpectedShippingDate(DateTime $orderDate): DateTime {
    return $orderDate->add(DateInterval::createFromDateString('3 day'));
}

$orderDate = new DateTime('2024-05-27');
$shippingDate = getExpectedShippingDate($orderDate);

// $orderDate = 2024-05-30
// $shippingDate = 2024-05-30

Dans l’exemple précédent, on peut voir que l’appel à la méthode getExpectedShippingDate a modifié la valeur de la date de notre objet $orderDate. En PHP les objets étant passés par référence et une instance de DateTime étant mutable, toute modification effectuée sur notre objet dans un bloc de code modifie la valeur de ce dernier dans le reste du code.

Pour éviter ce problème, vous l’aurez deviné, il faut utiliser une instance de DateTimeImmutable. Reprenons le code de notre fonction de calcul de la date prévisionnel d’envoi d’une commande:

function getExpectedShippingDate(DateTimeImmutable $orderDate): DateTimeImmutable {
    return $orderDate->add(DateInterval::createFromDateString('3 day'));
}

$orderDate = new DateTimeImmutable('2024-05-27');
$shippingDate = getExpectedShippingDate($orderDate);

// $orderDate = 2024-05-27
// $shippingDate = 2024-05-30

Contrairement à une instance de DateTime, DateTimeImmutable est un objet immuable. Cela signifie que lorsqu’une opération est effectuée sur ce dernier, PHP ne va pas modifier la valeur courante l’objet. Le moteur va créer une nouvelle instance de date avec la bonne valeur et la renvoyer comme résultat de la fonction. De ce fait, notre date $orderDate conserve sa valeur d’origine.

A partir de là, la question que l’on est en droit de se poser maintenant est: dans quel cas utiliser l’un ou l’autre ? Au risque de paraître un peu extrémiste, mon avis est que l’on ne devrait jamais utiliser DateTime. Le risque de créer un effet de bord est trop important, sans compter la difficulté à retrouver l’origine du problème. L’utilisation de DateTime étant à mon sens à proscrire, vous devriez systèmatiquement utiliser DateTimeImmutable.