DateTimeImmutable
The first time that my improved DateTime support made its way into PHP was officially in PHP 5.1, although the more advanced features such as the DateTime class only made it appearance in PHP 5.2. Since its introduction the DateTime class implementation suffered from one design mistake — arguably not something that even an RFC would have highlighted.
In PHP, if you do the following:
<?php
function formatNextMondayFromNow( DateTime $dt )
{
return $dt->modify( 'next monday' )->format( 'Y-m-d' );
}
$d = new DateTime();
echo formatNextMondayFromNow( $d ), "\n";
echo $d->format( 'Y-m-d' ), "\n";
?>
It displays:
2014-02-17 2014-02-17
The modify() method does not only return the modified DateTime object, but also changes the DateTime object it was called on. In an API like above, this is of course totally unexpected and the only way to avoid this behaviour is to do the following instead:
echo formatNextMondayFromNow( clone $d ), "\n";
This mutability property that all modifying methods of the DateTime class have is highly annoying, and something that I would now rather remove. But of course we cannot as that would break backwards compatibility.
So in PHP 5.5, after a few stumbles, I finally managed to rectify this. I did not change the original class's behaviour, but instead, I added a new class. The new DateTimeImmutable class which does not display this "mutable" behaviour, and only returns the modified object:
<?php
function formatNextMondayFromNow( DateTimeImmutable $dt )
{
return $dt->modify( 'next monday' )->format( 'Y-m-d' );
}
$d = new DateTimeImmutable();
echo formatNextMondayFromNow( $d ), "\n";
echo $d->format( 'Y-m-d' ), "\n";
?>
Which displays:
2014-02-17 2014-02-11
Both the old DateTime and the new DateTimeImmutable classes implement the DateTimeInterface interface. This interface defines all the methods that both classes implement. Of course, they can not be methods that change the object. That is why the interface is restricted to formatting and other read-only methods, such as getTimezone.
Perhaps in the future (PHP 6), we can replace the mutable DateTime class with the new DateTimeImmutable variant. Until then, you will have to take care of this yourself!
Comments
Hi Derick,
the DateTimeImmutable class should have another static method:
create(DateTimeInterface $dt) {
return $dt instanceof DateTimeImmutable
? $dt
: new DateTimeImmutable($dt)
}
such a method is important in a constructor:
class MyClass {
private $immutableDateTime;
public function __construct(DateTimeInterface $dt) {
$this->immutableDateTime = DateTimeImmutable::create($dt);
}
}
You don't want somebody from outside to modify the internal state of MyClass.
I miss a direct way to cast from one to the other.
Too bad you are using such an example to justify DateTimeImmutable. The formatNextMondayFromNow() should clone the date:
function formatNextMondayFromNow( DateTime $dt )
{
$dt = clone $dt;
return $dt->modify( 'next monday' )->format( 'Y-m-d' );
}
Or better, be broken into two parts:
$now->next('monday')->format();
Where next() would return a new instance representing the next something, here "monday".
To me, with this example, it looks like DateTimeImmutable is a solution to bad usages.
I created an extension to DateTime and all the yesterday, monday, utc, local, … magic properties return new instances. Only modify() actually modifies the instance. I'm quite happy with it.
@Thomas, @Per: I have added to PHP-5.6 a new method DateTimeImmutable::createFromMutable() that allows you to instantiate a non-mutable DateTimeImmutable variant based off a mutable DateTime object.
DateTimeImmutable::createFromMutable() is a good addition but conversely being able to do the opposite would have been great too DateTime::createFromImmutable()
This way switching from one class to the other would be less painfull.
Is it possible to make DateTime immutable in PHP 7 to avoid this madness?
@Daniel: Possible, but that is going to break quite a lot of code, and it's going to be difficult to spot/test. So that's not happening.
While we're at it. It would of course be nice to get rid of a mutable DateTime in PHP7 but I'm afraid that this would be too much of a break and Derick already commented on how important he considers backward compatibility.
But please add a method DateTimeImmutable::from(DateTimeInterface $dt).
This method is needed all the time when a Constructor accepts a DateTimeInterface. In this case one can either take a given DateTimeImmutable as is of create a new DateTimeImmutable from a given DateTime.
@Thomas: That method does exist:
And PHP 7 will have the createFromMutable method on DateTime too.
Life Line
Updated a restaurant
Created a bench
Updated a cafe
But I think my favourite photo was of this Carrion Crow in flight.
The new birds I saw, were mostly too far away to get good photos.
But I saw my first Spoonbill, Corn Bunting, and a flock of Black-tailed Godwits.
I had a lovely walk around RSPB Bowers Marsh yesterday, where I saw some expected birds, and a bunch of new species.
When I got there, there was this welcome committee of Starlings.
#BirdPhotography #nature #BirdsOfFediverse #Birds #Photography #RSPB
RSPB Bowers Marsh
Created 2 benches
I hiked 11.3km in 3h31m08s
Updated a pub
Updated a pub
Updated 4 pubs; Confirmed a pub
Created a restaurant
I walked 0.8km in 9m31s
I walked 2.1km in 16m42s
I walked 4.7km in 48m42s
I walked 7.4km in 1h16m10s
Updated a fast_food
Updated a cafe, a pet shop, and a bench; Confirmed a cafe, a convenience shop, and a motorcycle_repair shop
I walked 5.0km in 1h2m27s
I walked 1.1km in 10m08s
Updated a cafe; Confirmed 3 convenience shops, a fast_food, and a laundry shop
Created a fitness_centre; Updated an event_caterer office and a social_facility; Confirmed a restaurant and a pharmacy
I walked 7.6km in 1h29m58s
Updated a pub




Shortlink
This article has a short URL available: https://drck.me/dti-avg