Hello,
I encountered an issue with the following code:
var_dump(Carbon::parse(null));
Carbon version: 2.25.3
PHP version: 7.3.10
I expected to get:
But I actually get:
object(Carbon\Carbon)#3310 (3) {
["date"]=>
string(26) "2019-10-23 16:39:36.736934"
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "Europe/Ljubljana"
}
Is it expected behaviour, that executing Carbon::parse on null returns the current a Carbon object with the current time? If so, why is this undocumented?
Hello, it is documented:
API reference says for parse: returns Carbon
If it could return null, it would be: returns Carbon|null (as it is documented for make and explicitly mentioned "...but otherwise return null" for example).
Returning null just because one of the parameter passed is null is not a logical expectation. You should by default assume a method return the documented type unless the contrary is explicitly written.
Then Carbon extends DateTime so it inherits the behavior of the native PHP class and new DateTime(null) return the same as new DateTime('now') so Carbon takes the same assertion: null is now.
I see. Thanks for the explanation. I guess this is another quirk I will have to remember. 馃槄
There is no quirk here. If we would have been strict about it, we would have thrown an InvalidArgumentException because the documented behavior of parse() is parsing a string and null is not a string.
A car expect gas, if you put nothing in the reservoir, it won't work but the car won't disappear.
I can imagine parse(null) returning null could be convenient in a particular situation you encountered (such as casting from a nullable column of a database maybe and in this case you can use make), but I can't see a valid reason to handle null as a particular value with its own output type. It would be rather harmful for many users. Those kind of changes being breaking are in any case postponed to the next major version and should be justified and challenged with different codes to see if it's really better after the change than before:
echo Carbon::parse()->format('...');
$expiration = string or null
if (Carbon::parse($expiration)->isBefore('today')) ...
$event = string or null
echo Carbon::parse($event)->diffInDays('now');
As you can see with those examples, handling null as now can be useful and with no doubt, many applications in production would have similar codes and rely on this behavior.
Indeed you are correct, I stumbled upon this oddity whilst trying to store null into a nullable database model's field. To my surprise it stored the current time and well ... a ternary helped me out but for the life of me I couldn't figure out why it misbehaved that way. I would have expected either null or an Exception complaining that the argument must be a string or something in that way, however for it to return the same as new DateTime(null) is kind of upsetting to me.
As an analogy the Python library dateutil, which does basically the same thing as Carbon does for PHP, will throw a TypeError when you try to do something like dateutil.parser.parse(None). I was being naive and thought it would do something similar. I couldn't have been more wrong. 馃槼
No ternary needed, as I said, in your case what you need is make:
var_dump(Carbon::make(null)); // null
var_dump(Carbon::make('2019-06-15 12:34:54')); // Carbon instance
Oh wow, how on Earth did I miss that! Thanx! 鉂わ笍
Just ran into this today. In my opinion parse() should try to parse something. If you give it NULL it should throw an exception.
It would be definitely a high-impact breaking-change for many people. Use ::make() or create your own parse with typehint:
Carbon::macro('strictParse', static function (string $date) {
return static::parse($date);
});
var_dump(Carbon::strictParse('2019-06-15 12:34:54')); // Carbon instance
var_dump(Carbon::strictParse(null)); // Type error
Most helpful comment
No ternary needed, as I said, in your case what you need is
make: