<? phpukraine ЕКОСИСТЕМА
⌕Пошук по платформі
SYMFONY · ЩО НОВОГО

Що нового в Symfony 8.0

  1. 01Можливості ті самі, що в 7.4 LTS, але без жодного deprecated-коду. Серед видаленого XML-конфіги та fluent PHP-конфіг.
  2. 02Потрібен PHP 8.4: у коді фреймворку не лишилось запасних гілок для 8.2 і 8.3.
  3. 03Підтримку 8.0 завершено 31 липня 2026 року. Оновлюйтеся одразу на 8.1 або лишайтеся на 7.4 LTS.
СТАТУС Не підтримується
Реліз
27 листопада 2025
Останній патч
8.0.16
Активна підтримка до
31.07.2026
Безпека до
31.07.2026
НОВІ МОЖЛИВОСТІ · 4

Нові можливості

1.1 · 8.0

Нативні lazy objects без запасних гілок

У коді 7.4.0, не рахуючи тестів, є 54 порівняння PHP_VERSION_ID з 80400 у 32 файлах, бо той самий код має працювати й на PHP 8.2. У 8.0.0 жодного. Контейнер завжди створює lazy-сервіси через ReflectionClass::newLazyGhost(), тому lazy-сервісом без обхідних шляхів може бути й final, і readonly клас. DomCrawler завжди парсить HTML через Dom\HTMLDocument, у HtmlSanitizer лишився тільки NativeParser на тому ж класі, а symfony/polyfill-php84 і masterminds/html5 зникли із залежностей компонентів.

+ SYMFONY 8.0
// DependencyInjection\LazyProxy\Instantiator\LazyServiceInstantiator
if ($asGhostObject) {
    return new \ReflectionClass($definition->getClass())->newLazyGhost(
        static function ($ghost) use ($realInstantiator) { $realInstantiator($ghost); }
    );
}
− SYMFONY 7.4
// DependencyInjection\LazyProxy\Instantiator\LazyServiceInstantiator
if (\PHP_VERSION_ID >= 80400 && $asGhostObject) {
    return (new \ReflectionClass($definition->getClass()))->newLazyGhost(
        static function ($ghost) use ($realInstantiator) { $realInstantiator($ghost); }
    );
}

// далі для PHP 8.2 і 8.3 клас, згенерований з LazyGhostTrait
1.2 · 7.4 і 8.0

PHP-конфіг масивами

Формат зʼявився одночасно в 7.4 і 8.0, детальніше на сторінці Symfony 7.4. Для 8.0 він важливіший: старий fluent-конфіг через config builders тут уже не завантажиться, як і XML. PHP-файл повертає масив тієї ж структури, що й YAML, а згенерований config/reference.php описує її array shapes для IDE та PHPStan.

+ SYMFONY 8.0
// config/packages/security.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

return App::config([
    'security' => [
        'firewalls' => [
            'main' => [
                'pattern' => '^/*',
                'lazy' => true,
            ],
        ],
        'access_control' => [
            ['path' => '^/admin', 'roles' => 'ROLE_ADMIN'],
        ],
    ],
]);
− SYMFONY 7.4
// config/packages/security.php
use Symfony\Config\SecurityConfig;

return static function (SecurityConfig $security) {
    $security->firewall('main')
        ->pattern('^/*')
        ->lazy(true);
    $security->accessControl(['path' => '^/admin', 'roles' => 'ROLE_ADMIN']);
};
1.3 · 7.4 і 8.0

#[MapInput] у консольних командах

Спільне з 7.4, детальніше на сторінці Symfony 7.4. Invokable-команда отримує аргументи й опції одним обʼєктом з атрибутом #[MapInput], рядок із консолі сам перетворюється на backed enum, а #[Ask] питає відсутній аргумент без власного interact(). На 8.0 PHP 8.4 гарантований, тож нормалізацію можна покласти в property hooks самого DTO.

+ SYMFONY 8.0
class CreateUserInput
{
    #[Argument]
    public string $email {
        set(string $value) {
            $this->email = strtolower(trim($value));
        }
    }

    #[Option]
    public bool $admin = false;
}

#[AsCommand('app:create-user')]
class CreateUserCommand
{
    public function __invoke(#[MapInput] CreateUserInput $input): int
    {
        // $input->email уже очищений, $input->admin типу bool
        return Command::SUCCESS;
    }
}
− SYMFONY 7.4
#[AsCommand('app:create-user')]
class CreateUserCommand extends Command
{
    protected function configure(): void
    {
        $this
            ->addArgument('email', InputArgument::REQUIRED)
            ->addOption('admin', null, InputOption::VALUE_NONE);
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $email = strtolower(trim($input->getArgument('email')));
        $admin = $input->getOption('admin');

        return Command::SUCCESS;
    }
}
1.4 · 7.4 і 8.0

Багатокрокові форми

Form flow прийшов у 7.4 і так само працює в 8.0, детальніше на сторінці Symfony 7.4. Кожен крок описується звичайним form type, а addStep() складає їх у послідовність. Поточний крок живе у властивості даних, заданій через step_property_path, і заодно стає групою валідації. У контролері додаються лише isFinished() і getStepForm().

+ SYMFONY 8.0
class UserSignUpType extends AbstractFlowType
{
    public function buildFormFlow(FormFlowBuilderInterface $builder, array $options): void
    {
        $builder->addStep('personal', PersonalType::class);
        $builder->addStep('account', AccountType::class);
        $builder->add('navigator', NavigatorFlowType::class);
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => User::class,
            'step_property_path' => 'currentStep',
        ]);
    }
}

// у контролері
$flow = $this->createForm(UserSignUpType::class, new User())->handleRequest($request);

if ($flow->isSubmitted() && $flow->isValid() && $flow->isFinished()) {
    return $this->redirectToRoute('signup_success');
}

return $this->render('signup.html.twig', ['form' => $flow->getStepForm()]);
ПРОДУКТИВНІСТЬ · 1

Продуктивність

2.1 · 7.4 і 8.0

CachingHttpClient на компоненті Cache

Переписаний клієнт є і в 7.4, детальніше на сторінці Symfony 7.4. Відповіді кешуються за RFC 9111 у будь-якому tag-aware пулі, наприклад Redis, а у фреймворку вистачає опції caching.cache_pool у scoped-клієнта. Передати Store, як раніше, у 8.0 вже не вийде: конструктор приймає лише TagAwareCacheInterface.

+ SYMFONY 8.0
use Symfony\Component\Cache\Adapter\FilesystemTagAwareAdapter;
use Symfony\Component\HttpClient\CachingHttpClient;
use Symfony\Component\HttpClient\HttpClient;

$cache = new FilesystemTagAwareAdapter();
$client = new CachingHttpClient(HttpClient::create(), $cache);
− SYMFONY 7.4
use Symfony\Component\HttpClient\CachingHttpClient;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpKernel\HttpCache\Store;

$store = new Store('/path/to/cache/storage/');
$client = new CachingHttpClient(HttpClient::create(), $store);
БЕЗПЕКА · 1

Безпека

3.1 · 7.4 і 8.0

Підпис повідомлень Messenger

Зʼявився в 7.4 разом з 8.0, детальніше на сторінці Symfony 7.4. З sign: true повідомлення для цього обробника підписується HMAC на основі kernel.secret, а підпис іде в заголовках Body-Sign і Sign-Algo. Якщо при отриманні підпису немає або він не збігається, Messenger кидає InvalidMessageSignatureException і повідомлення не обробляє. Для RunProcessMessage і RunCommandMessage підпис увімкнено з коробки.

+ SYMFONY 8.0
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

#[AsMessageHandler(sign: true)]
class SmsNotificationHandler
{
    public function __invoke(SmsNotification $message): void
    {
        // ...
    }
}
BREAKING

Ламає сумісність

Перевірте це до оновлення: такий код перестане працювати або поводитиметься інакше.

PHP 8.4Компоненти й бандли 8.0 вимагають php >=8.4. Symfony 7.4 ще працює на PHP 8.2.
XML-конфігураціяXmlFileLoader видалено з DependencyInjection і Routing, тож services.xml і маршрути в XML не завантажаться. Переносьте їх у YAML або PHP.
Fluent PHP-конфігЗамикання з параметром на кшталт SecurityConfig $security більше не працює. PHP-файл повертає масив через App::config().
Annotation-неймспейсиRouting\Annotation\Route і Serializer\Annotation\* видалено. Ті самі класи лежать у неймспейсі Attribute.
Command::getDefaultName()Видалено разом із getDefaultDescription(), назву й опис задає #[AsCommand]. Application::add() замінено на addCommand().
Request::get()Метод видалено. Беріть значення явно з $request->attributes, query або request.
eraseCredentials()Методу більше немає в UserInterface і TokenInterface. Пароль та інші чутливі поля прибирайте із серіалізації в __serialize().
Voter::voteOnAttribute()Абстрактний метод отримав параметр ?Vote $vote = null, тож voter без нього в сигнатурі дає fatal error. Те саме з ?TokenInterface $token = null у UserCheckerInterface::checkPostAuth().
hide_user_not_foundОпцію в security.yaml замінено на expose_security_errors зі значеннями none, account_status і all.
#[TaggedIterator] і #[TaggedLocator]Замість них #[AutowireIterator] і #[AutowireLocator], а в YAML замість !tagged пишіть !tagged_iterator.
Auto-mapping сутностей DoctrineСутність у контролері автоматично шукається лише за {id}. Для інших полів пишіть {slug:product} у маршруті або #[MapEntity].
Doctrine DBAL 3 і ORM 2symfony/doctrine-bridge 8.0 конфліктує з doctrine/dbal нижче 4.3 і doctrine/orm нижче 3.4.
Опції констрейнтів масивомЗапис Length(['min' => 3]) у new і в атрибутах більше не працює, лише іменовані аргументи: Length(min: 3).
UrlType і UrlUrlType більше не дописує http:// до адреси без протоколу, а констрейнт Url тепер вимагає домен верхнього рівня.
LazyGhostTrait і LazyProxyTraitТрейти VarExporter і ProxyHelper::generateLazyGhost() видалено. Використовуйте нативні lazy objects з PHP 8.4.

Як оновитися

0 / 7