В 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.