В Laravel 8.53 появились касты immutable_date и immutable_datetime преобразующие даты в Иммутабельные (Неизменяемые, Immutable). Я бы предпочел, чтобы фреймворк по умолчанию использовал такой вид дат. Давайте разберемся, что это такое и зачем это нужно.
Рассмотрим пример:
$start = Carbon\Carbon::now(); $end = $start->addDay();
Если вы посмотрите на разницу между этими датами, то будете удивлены.
$end->diffForHumans($start); // выведет «1 second before»
Почему так?
Экземпляры Carbon, наследующие класс DateTime из PHP — мутабельные (изменяемые, mutable) объекты по умолчанию.
Мутабельный объект — это объект, любые модификации которого изменяют или мутируют исходный экземпляр объекта. Если вы продолжите манипуляции с указанной выше переменной $end, то обнаружите, что исходная переменная $start также обновляется, потому что $end это просто ссылка на первоначально созданный объект ($start).
$end->addHour(); $end->eq($start); // true
Вы можете обойти эту проблему, используя метод clone():
$start = Carbon\Carbon::now(); $end = $start->clone()->addDay(); $end->diffForHumans($start); // выведет «1 day after»
Однако это слишком длинно и чревато ошибками, поскольку вам приходится помнить, что каждый раз нужно вызывать метод clone().
Это может привести к запутанности вашего кода, ваших тестов и другим непонятным ошибкам приложения.
Иммутабельность — вот решение
К счастью, PHP — и, соответственно, Carbon, — обеспечивает иммутабельную DateTime реализацию DateTimeInterface.
Вместо Carbon вы можете использовать CarbonImmutable.
$start = Carbon\CarbonImmutable::now(); $end = $start->addDay(); $end->diffForHumans($start); // 1 day after
Однако это всё еще немного не то. Ваша мышечная память скорей всего время от времени будет использовать просто Carbon, а не CarbonImmutable, что будет приводить к ошибкам.
Фасад Date
Laravel-фасад, представленный в Laravel 5.8, обеспечивает хороший доступ для использования класса Illuminate\Support\Carbon с дополнительным бонусом: возможность настроить класс даты по умолчанию для использования во всём вашем приложении.
use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
//
}
public function boot()
{
Date::use(CarbonImmutable::class);
}
}
Теперь всякий раз, когда вы используете хелпер now() или фасад Date в своем коде, то всегда получаете экземпляр CarbonImmutable. Точно так же, если вы используете метод freshTimestamp() в модели или используете какие-либо касты, то они всегда будут возвращаться как экземпляр CarbonImmutable.
Предостережение
Возможно вы используете напрямую класс Carbon в своем приложении, тогда вам нужно заменить его вызовы на фасад Date.
Хорошая новость заключается в том, что, поскольку это статический метод доступа к базовому экземпляру Carbon, единственное, что вам нужно изменить, это ваш оператор импорта (Carbon\Carbon или Illuminate\Support\Carbon поменять на Illuminate\Support\Facades\Date) и использования (на Date), а всё остальное должно заработать.
Автор: Michael Dyrynda
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.
