Подписывайтесь на наш Telegram-канал и будьте в курсе всех событий
Поделитесь своим кодом и идеями!
Поделитесь своим кодом и идеями!

Руководство по обновлению

Изменения с высоким уровнем влияния

Изменения со средним уровнем влияния

Изменения с низким уровнем влияния

Обновление с 12.x до 13.0

Оценочное время обновления: 10 минут

Мы стараемся документировать все возможные критические изменения. Поскольку часть этих изменений находится в редко используемых областях фреймворка, только некоторые из них могут затронуть ваше приложение. Чтобы сэкономить время, можно использовать Shift. Shift – поддерживаемый сообществом сервис, который автоматизирует обновления Laravel.

Обновление с помощью AI

Вы можете автоматизировать обновление с помощью Laravel Boost. Boost – официальный MCP-сервер, который предоставляет вашему AI-ассистенту направленные prompt для обновления. После установки в любое приложение Laravel 12 используйте slash-команду /upgrade-laravel-v13 в Claude Code, Cursor, OpenCode, Gemini или VS Code, чтобы начать обновление до Laravel 13. Для этой команды требуется Laravel Boost ^2.0.

Обновление зависимостей

Вероятность влияния: высокая

Зависимости Composer

Обновите следующие зависимости в вашем файле composer.json:

  • laravel/framework до ^13.0
  • laravel/boost до ^2.0
  • laravel/tinker до ^3.0
  • phpunit/phpunit до ^12.0
  • pestphp/pest до ^4.0

Обновление Laravel Installer

Если вы используете Laravel installer CLI tool для создания новых Laravel-приложений, обновите installer для совместимости с Laravel 13.x.

Если Laravel installer установлен через composer global require, обновите installer командой composer global update:

composer global update laravel/installer

Или, если вы используете копию установщика Laravel, поставляемую с Laravel Herd, обновите Herd до последнего релиза.

Cache

Вероятность влияния: низкая

Префиксы кеша и ключей Redis по умолчанию в Laravel теперь используют суффиксы через дефис.

В большинстве приложений это изменение не применяется, потому что конфигурационные файлы уровня приложения уже определяют эти значения. В основном оно влияет на приложения, которые полагаются на резервную конфигурацию уровня фреймворка, когда соответствующие значения отсутствуют в конфигурации приложения.

Если ваше приложение зависит от этих сгенерированных значений по умолчанию, ключи кеша и имена session cookie могут измениться после обновления:

// Laravel <= 12.x
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_cache_';
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_database_';
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_session';

// Laravel >= 13.x
Str::slug((string) env('APP_NAME', 'laravel')).'-cache-';
Str::slug((string) env('APP_NAME', 'laravel')).'-database-';
Str::slug((string) env('APP_NAME', 'laravel')).'-session';

Чтобы сохранить прежнее поведение, явно настройте CACHE_PREFIX, REDIS_PREFIX и SESSION_COOKIE в окружении.

Контракты Store и Repository: touch

Вероятность влияния: очень низкая

Контракты кеша теперь включают метод touch для продления TTL элементов. Если вы поддерживаете пользовательские реализации хранилища кеша, добавьте этот метод:

// Illuminate\Contracts\Cache\Store
public function touch($key, $seconds);

Конфигурация кеша serializable_classes

Вероятность влияния: средняя

Конфигурация cache приложения по умолчанию теперь включает опцию serializable_classes, установленную в false. Это усиливает безопасность десериализации кеша и помогает предотвратить цепочки атак через PHP-десериализацию, если APP_KEY вашего приложения утечет. Если приложение намеренно хранит PHP-объекты в кеше, явно перечислите классы, которые можно десериализовать:

'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
    App\Support\CachedPricingSnapshot::class,
],

Если приложение раньше полагалось на десериализацию произвольных кешированных объектов, нужно перенести такой код на явные списки разрешенных классов или на payload кеша без объектов, например массивы.

Контейнер

Container::call и значения nullable-классов по умолчанию

Вероятность влияния: низкая

Container::call теперь учитывает значения по умолчанию для nullable-параметров классов, когда привязка отсутствует, что соответствует поведению внедрения зависимостей через конструктор, представленному в Laravel 12:

$container->call(function (?Carbon $date = null) {
    return $date;
});

// Laravel <= 12.x: Carbon instance
// Laravel >= 13.x: null

Если ваша логика внедрения зависимостей при вызове метода зависела от прежнего поведения, ее может потребоваться обновить.

Контракты

Контракт Dispatcher: dispatchAfterResponse

Вероятность влияния: очень низкая

Контракт Illuminate\Contracts\Bus\Dispatcher теперь включает метод dispatchAfterResponse($command, $handler = null).

Если вы поддерживаете пользовательскую реализацию диспетчера, добавьте этот метод в ваш класс.

Контракт ResponseFactory: eventStream

Вероятность влияния: очень низкая

Контракт Illuminate\Contracts\Routing\ResponseFactory теперь включает сигнатуру eventStream.

Если вы поддерживаете пользовательскую реализацию этого контракта, добавьте этот метод.

Контракт MustVerifyEmail: markEmailAsUnverified

Вероятность влияния: очень низкая

Контракт Illuminate\Contracts\Auth\MustVerifyEmail теперь включает markEmailAsUnverified().

Если у вас есть пользовательская реализация этого контракта, добавьте этот метод для совместимости.

База данных

Database upsert с MySQL или MariaDB

Вероятность влияния: средняя

Laravel теперь проверяет, что caller передал непустое значение uniqueBy, и выбрасывает InvalidArgumentException вместо генерации некорректного SQL.

Хотя database drivers MariaDB и MySQL игнорируют значение uniqueBy и всегда используют primary и unique indexes таблицы для обнаружения существующих записей, validation все равно применяется. Если uniqueBy пустой, будет выброшен InvalidArgumentException.

Запросы MySQL DELETE с JOIN, ORDER BY и LIMIT

Вероятность влияния: низкая

Laravel теперь компилирует полные запросы DELETE ... JOIN, включая ORDER BY и LIMIT, для грамматики MySQL.

В предыдущих версиях выражения ORDER BY / LIMIT могли молча игнорироваться для удалений с JOIN. В Laravel 13 эти выражения включаются в сгенерированный SQL. В результате движки баз данных, которые не поддерживают такой синтаксис, например стандартные варианты MySQL / MariaDB, теперь могут выбросить QueryException вместо выполнения неограниченного удаления.

Eloquent

Загрузка моделей и вложенное создание экземпляров

Вероятность влияния: очень низкая

Создание нового model instance во время booting этой же model теперь запрещено и выбрасывает LogicException.

Это влияет на код, который создает models внутри model boot methods или trait boot* methods:

protected static function boot()
{
    parent::boot();

    // Больше не разрешено во время booting...
    (new static())->getTable();
}

Перенесите эту логику за пределы boot cycle, чтобы избежать nested booting.

Генерация имени polymorphic pivot table

Вероятность влияния: низкая

Когда table names выводятся для polymorphic pivot models с custom pivot model classes, Laravel теперь генерирует pluralized names.

Если приложение зависело от прежних singular inferred names для morph pivot tables и использовало custom pivot classes, явно определите table name на pivot model.

Сериализация коллекций моделей восстанавливает eager-loaded relations

Вероятность влияния: низкая

Когда коллекции Eloquent models сериализуются и восстанавливаются, например в queued jobs, eager-loaded relations теперь восстанавливаются для models коллекции.

Если ваш код зависел от отсутствия relations после deserialization, эту логику может потребоваться изменить.

HTTP Client

Signatures Response::throw и throwIf в HTTP Client

Вероятность влияния: очень низкая

Методы response HTTP client теперь объявляют callback parameters в method signatures:

public function throw($callback = null);
public function throwIf($condition, $callback = null);

Если вы переопределяете эти методы в custom response classes, убедитесь, что method signatures совместимы.

Notifications

Default subject письма сброса пароля

Вероятность влияния: очень низкая

Default subject письма сброса пароля Laravel изменился:

// Laravel <= 12.x
Reset Password Notification

// Laravel >= 13.x
Reset your password

Если ваши tests, assertions или translation overrides зависят от прежней строки по умолчанию, обновите их.

Queued notifications и отсутствующие models

Вероятность влияния: очень низкая

Queued notifications теперь учитывают атрибут #[DeleteWhenMissingModels] и свойство $deleteWhenMissingModels, определенные на notification class.

В предыдущих версиях missing models могли все еще приводить к сбою queued notification jobs в случаях, когда вы ожидали их удаления.

Queue

Exception payload события JobAttempted

Вероятность влияния: низкая

Событие Illuminate\Queue\Events\JobAttempted теперь предоставляет exception object или null через $exception, заменяя прежнее boolean-свойство $exceptionOccurred:

// Laravel <= 12.x
$event->exceptionOccurred;

// Laravel >= 13.x
$event->exception;

Если вы слушаете это событие, обновите код слушателя.

Переименование свойства события QueueBusy

Вероятность влияния: низкая

Свойство $connection события Illuminate\Queue\Events\QueueBusy переименовано в $connectionName для согласованности с другими событиями очереди.

Если ваши слушатели обращаются к $connection, обновите их на $connectionName.

Добавления методов в контракт Queue

Вероятность влияния: очень низкая

Контракт Illuminate\Contracts\Queue\Queue теперь включает методы проверки размера очереди, которые раньше были объявлены только в docblocks.

Если вы поддерживаете пользовательские реализации драйвера очереди для этого контракта, добавьте реализации для:

  • pendingSize
  • delayedSize
  • reservedSize
  • creationTimeOfOldestPendingJob

Маршрутизация

Приоритет регистрации domain routes

Вероятность влияния: низкая

Routes с явно указанным domain теперь имеют приоритет над non-domain routes при route matching.

Это позволяет catch-all subdomain routes вести себя согласованно, даже если non-domain routes зарегистрированы раньше. Если ваше приложение зависело от прежнего registration precedence между domain и non-domain routes, проверьте route matching behavior.

Scheduling

Timing регистрации withScheduling

Вероятность влияния: очень низкая

Schedules, зарегистрированные через ApplicationBuilder::withScheduling(), теперь откладываются до момента разрешения Schedule.

Если ваше приложение зависело от немедленного timing регистрации schedule во время bootstrap, эту логику может потребоваться изменить.

Security

Защита от подделки запросов

Вероятность влияния: высокая

CSRF middleware Laravel переименован с VerifyCsrfToken в PreventRequestForgery и теперь включает проверку origin запроса с помощью заголовка Sec-Fetch-Site.

VerifyCsrfToken и ValidateCsrfToken остаются устаревшими псевдонимами, но прямые ссылки следует обновить на PreventRequestForgery, особенно при исключении middleware в тестах или определениях маршрутов:

use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;

// Laravel <= 12.x
->withoutMiddleware([VerifyCsrfToken::class]);

// Laravel >= 13.x
->withoutMiddleware([PreventRequestForgery::class]);

API конфигурации middleware теперь также предоставляет preventRequestForgery(...).

Support

Binding callback для extend в manager

Вероятность влияния: низкая

Custom driver closures, зарегистрированные через manager methods extend, теперь bound к manager instance.

Если раньше вы полагались на другой bound object, например service provider instance, как $this внутри этих callbacks, перенесите такие значения в closure captures через use (...).

Сброс Str factories между тестами

Вероятность влияния: низкая

Laravel теперь сбрасывает custom Str factories во время test teardown.

Если ваши tests зависели от того, что custom UUID / ULID / random string factories сохраняются между test methods, задавайте их в каждом соответствующем test или setup hook.

Js::from по умолчанию использует unescaped Unicode

Вероятность влияния: очень низкая

Illuminate\Support\Js::from теперь по умолчанию использует JSON_UNESCAPED_UNICODE.

Если ваши tests или frontend output comparisons зависели от escaped Unicode sequences, например \u00e8, обновите expectations.

Utilities

Symfony PHP 8.5 Polyfill и конфликты global functions

Вероятность влияния: низкая

Laravel 13 добавляет dependency symfony/polyfill-php85. На версиях PHP ниже 8.5 этот polyfill определяет global functions, такие как array_first() и array_last(), если они не были определены ранее во время bootstrap.

Эти функции могут конфликтовать с legacy helper packages вроде laravel/helpers или custom global helpers с такими же именами. Например, исторический helper array_first() принимал callback, чтобы вернуть первый подходящий element, тогда как polyfilled version возвращает только первый element массива.

Чтобы избежать конфликтов и обеспечить согласованное поведение между версиями PHP, предпочитайте методы Illuminate\Support\Arr:

use Illuminate\Support\Arr;

Arr::first($array, function ($value) {
  return /* condition */;
});

Представления

Имена Bootstrap-представлений для пагинации

Вероятность влияния: низкая

Внутренние имена представлений пагинации для значений Bootstrap 3 по умолчанию теперь явные:

// Laravel <= 12.x
pagination::default
pagination::simple-default

// Laravel >= 13.x
pagination::bootstrap-3
pagination::simple-bootstrap-3

Если ваше приложение напрямую ссылается на старые имена представлений пагинации, обновите эти ссылки.

Разное

Мы также рекомендуем просмотреть изменения в GitHub-репозитории laravel/laravel. Хотя многие из этих изменений не обязательны, возможно, вы захотите синхронизировать эти файлы с вашим приложением. Некоторые изменения будут описаны в этом руководстве по обновлению, но другие, например изменения файлов конфигурации или комментариев, не будут. Вы можете легко посмотреть изменения с помощью инструмента сравнения GitHub и выбрать, какие обновления важны для вас.