php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79975 DateTime::createFromFormat returns static type
Submitted: 2020-08-13 22:26 UTC Modified: 2022-07-28 15:20 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: corey dot taylor dot fl at gmail dot com Assigned:
Status: Wont fix Package: Date/time related
PHP Version: 8.0.0beta1 OS:
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: corey dot taylor dot fl at gmail dot com
New email:
PHP Version: OS:

 

 [2020-08-13 22:26 UTC] corey dot taylor dot fl at gmail dot com
Description:
------------
I don't know if this is actually a bug or intended behavior or undefined behavior. However, since it's been consistent up to 8.0.0beta1, I thought I'd report the change.

https://3v4l.org/dgunY


DateTime::createFromFormat() used to always return a DateTime instance if called from a class that extended DateTime and wrapped createFromFormat().

Now, it is returning the static type. In this example,that is an ExtendsDateTime instance.

https://bugs.php.net/bug.php?id=60302

Looking, I see a very old bug that suggests this was supposed to be the fixed behavior, but clearly wasn't. We have some low level framework behavior keyed off the type of instance constructed, so we'd like to make sure this is the intended switch for PHP 8.


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-08-13 22:38 UTC] derick@php.net
This is indeed an intended big fix. As this change doesn't violate LSP (the inherited child class still follows the is_a relationship with DateTime), how does it cause a problem in your situation?
 [2020-08-13 23:17 UTC] corey dot taylor dot fl at gmail dot com
As part of the Chronos (date/time library), we have a Date type that wraps DateTime and handles ensuring date-only values.

There is logic that checks if creating an instance from a Date object or not to determine what to fix up. With this change, the unfixed instance is simply cloned.

Since DateTime::createFromFormat('Y-m-d') takes the current time all this logic was added to ensure construction was valid.

To be clear, this behavior seems like the correct behavior and should have been the original behavior, but since this will take some re-design to work with PHP 7 and 8, it's worth checking this won't revert back.
 [2020-08-14 09:33 UTC] corey dot taylor dot fl at gmail dot com
One issue we will have is knowing when this object was created.

https://3v4l.org/k5gDZ

Is there no indication that the derived class was instantiated from createFromFormat()?
 [2020-08-15 16:23 UTC] mark at mark-story dot com
If the subclass is going to be returned by DateTime::createFromFormat() shouldn't its constructor also be used?

https://3v4l.org/LqeX2

Shows that while the subclass is returned, its constructor hasn't been returned which is something I would expect.
 [2020-08-21 09:38 UTC] corey dot taylor dot fl at gmail dot com
Looking into this further, I see how calling the constructor would be tricky.

The time would need to be calculated from the createFromFormat parameters and then converted to a standard/ISO format to pass to the constructor to actually instantiate the object.

However, it's really an awkward scenario to deal with since there's no initialization of properties through the derived constructor.
 [2020-08-21 09:47 UTC] derick@php.net
I don't there should be a reason why a factory creation method should call a constructor? Normal PHP also does not do this: https://3v4l.org/ekOtT
 [2020-08-21 09:51 UTC] corey dot taylor dot fl at gmail dot com
I'm sorry, I don't follow your example. It isn't a factory. It's just a static function that echos.

Can you explain the logic behind a factory not constructing?
 [2020-08-24 07:33 UTC] nikic@php.net
Yeah, the current behavior here is not great. I think it should either continue returning self, or call the constructor for extended classes.

A workaround would be to do something like

class MyDateTime {
    public static function createFromFormat(...$args) {
        $date = parent::createFromFormat(...$args);
        // Do the rest of your initialization here
        return $date;
    }
}
 [2020-08-24 07:54 UTC] corey dot taylor dot fl at gmail dot com
Our work-around is constructing the object twice. We take the result of parent::createFromFormat() and format() the full string then new static() to ensure the constructor is called which is necessary as it clamps values.

I tried implementing the logic I mentioned of using timelib to calculate the time formatting a similar string to then construct the instance. However, as my first attempt working in php, figuring out how to execute the derived constructor and such from the date code proved impossible.
 [2020-11-14 21:18 UTC] carusogabriel@php.net
-Package: *General Issues +Package: Date/time related
 [2022-07-28 15:20 UTC] derick@php.net
-Status: Open +Status: Wont fix
 [2022-07-28 15:20 UTC] derick@php.net
I am inclined not to change this back now again in PHP 8.2, as it's been two years and changing it back will just end up causing more work.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 12:01:31 2024 UTC