Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use `DateTimeInterface` in my php project?

Recently, I discovered that there is a DateTimeInterface. As I was working with \DateTime and \DateTimeImmutable, I thought that it'd be good to typehint for.

Yet on the Changelog on php.net it says that since 5.5.8:

Trying to implement DateTimeInterface raises a fatal error now. Formerly implementing the interface didn't raise an error, but the behavior was erroneous.

This reads that I never be able to implement my own CustomDateTime class implementing the DateTimeInterface, which seems rather odd.

Should I use the DateTimeInterface in my userland code?

My gut feeling tells me not to. Yet it also doesn't feel right to typehint the object, i.e.

@var \DateTime|\DateTimeImmutable|\MyCustomDateTime
like image 896
k0pernikus Avatar asked Jun 03 '16 08:06

k0pernikus


1 Answers

You can use the DateTimeInterface typehint when you expect either one of the native DateTime variants, e.g. \DateTime or \DateTimeImmutable.

But as the docs say

It is not possible to implement this interface with userland classes.

So if you plan to implement \DateTimeInterface with your own implementation, this will not work, e.g.

class MyDateTime implements \DateTimeInterface {} // will raise an error

However, you can create your own interface and adapt the native DateTime classes.

interface MyDateTime { /* some methods */ }

class NativeDateTime implements MyDateTime 
{
    private $dateTime;

    public function __construct($args = 'now') {
        $this->dateTime = new \DateTimeImmutable($args);
    }

   /* some methods */
}

Or you can extend the native DateTime variants, which will then implement the DateTimeInterface obviously, e.g.

class MyDateTime extends \DateTimeImmutable 
{
    /* your modifications */
}

var_dump(new MyDateTime instanceof \DateTimeInterface); // true

Details why you cannot implement your own classes implementing \DateTimeInterface:

  • https://github.com/php/php-src/pull/512
  • https://www.mail-archive.com/[email protected]/msg79534.html

tl;dr core functions that accept DateTime and DateTimeImmutable (DateTimeInterface basically) operate directly on timelib structures hence they will break if you pass them a user-defined class. There's a workaround though - it's to always call user-defined class's method directly from built-in functions, so if you would call (new DateTime())->diff(new UserDefinedDateTime()) it would call UserDefinedDateTime#diff in the end which would need to implement the logic.

like image 58
Gordon Avatar answered Oct 04 '22 00:10

Gordon