PHP Framework

Symfony

O Symfony é tanto um conjunto de componentes PHP reutilizáveis quanto um framework completo construído a partir deles. Ele prioriza estrutura, estabilidade e manutenibilidade de longo prazo em escala em vez de conveniência imediata.

advanced15 min readUpdated 16 de set. de 2026
src/Controller/BlogController.php
php
<?php
// src/Controller/BlogController.php

namespace App\Controller;

use App\Repository\PostRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class BlogController extends AbstractController
{
    #[Route('/blog/{slug}', name: 'blog_show')]
    public function show(string $slug, PostRepository $posts): Response
    {
        $post = $posts->findOneBy(['slug' => $slug]);

        if (!$post) {
            throw $this->createNotFoundException('Post not found');
        }

        return $this->render('blog/show.html.twig', [
            'post' => $post,
        ]);
    }
}
Lançado
2005
Criador
Fabien Potencier
Linguagem
PHP
Arquitetura
Componentes mais framework completo
ORM
Doctrine
CLI
bin/console
Config
YAML, XML ou PHP

Por que importa

Por que empresas escolhem o Symfony

Componentes que você pode usar em qualquer lugar

HttpFoundation, Routing, Console, Mailer e Serializer são bibliotecas independentes. Você pode adotar uma delas sem o framework, e grande parte do ecossistema PHP já faz isso.

Estabilidade e suporte de longo prazo

O Symfony oferece versões de suporte de longo prazo (LTS) com um caminho de depreciação documentado, tornando as atualizações previsíveis em vez de exigirem reescritas.

Flex e recipes

O Symfony Flex configura bundles e gera os arquivos de configuração para você, transformando a adição de uma funcionalidade em um simples composer require.

O panorama completo

Componentes, bundles, container

Bibliotecas desacopladas que você pode usar em qualquer lugar, bundles que empacotam funcionalidades e um container que conecta tudo.

Componentes

Reuso

Bibliotecas independentes para HTTP, roteamento, console, e-mail e serialização que funcionam em qualquer projeto PHP.

Bundles

Pacote

Bundles agrupam rotas, serviços, configurações e templates em uma unidade distribuível, conectada por recipes do Flex.

Container

Conexão

Um service container compilado constrói seu grafo de objetos e realiza o autowiring de dependências do construtor automaticamente.

HTML5 de uma olhada

A caixa de ferramentas do Symfony

Componentes

Bibliotecas independentes que você pode usar em qualquer projeto PHP, com ou sem o framework.

Bundles

Funcionalidades empacotadas que reúnem rotas, serviços, configurações e templates.

Flex recipes

Plugins do Composer que configuram bundles e criam os arquivos de configuração automaticamente.

Roteamento por atributos

Declare rotas ao lado da ação do controller usando atributos do PHP 8.

Doctrine

Um ORM de data-mapper com entidades, repositórios e migrações.

Console

O bin/console gera código, executa migrações, limpa o cache e consome filas.

Uma breve historia

Um framework e os componentes por trás dele

  1. 2005

    Symfony 1

    Fabien Potencier lança um framework para seus próprios projetos, inspirado por Rails e Mojavi.

    05
  2. 2011

    Symfony 2

    Uma reescrita completa construída a partir de componentes desacoplados que outros projetos podem reutilizar.

    11
  3. 2015

    Symfony 3

    Depreciações e uma API mais limpa preparam o ecossistema para futuras versões major.

    15
  4. 2019

    Symfony 4 e Flex

    As recipes do Flex automatizam a configuração de bundles e tornam as aplicações drasticamente mais leves.

    19
  5. 2023

    Symfony 7

    Atributos do PHP 8, propriedades tipadas e padrões modernos em todo o framework.

    23
  6. Hoje

    A sala de máquinas do PHP

    Os componentes do Symfony alimentam o Laravel, Drupal, phpBB e milhares de bibliotecas.

    Hoje

O guia completo

Symfony: Tudo que voce precisa saber

O que é Symfony?

O Symfony é duas coisas ao mesmo tempo. Ele é um conjunto de componentes PHP reutilizáveis — HttpFoundation, Routing, Console, Mailer, Serializer e dúzias de outros — e também é um framework web completo montado a partir desses componentes. Essa natureza dual explica quase tudo sobre ele: o framework é estável porque suas partes são estáveis, e suas partes são úteis por si só.

Criado por Fabien Potencier em 2005 e mantido pela SensioLabs, o Symfony tornou-se a “sala de máquinas” do PHP moderno. O Laravel é construído sobre componentes do Symfony, o Drupal e o phpBB dependem deles, e milhares de bibliotecas os utilizam sem nunca tocar no framework completo.

O Symfony exige mais de você do que um framework “batteries-included”. Em troca, ele entrega um sistema sobre o qual você pode raciocinar, estender e atualizar por anos.

Componentes: o produto real

Os componentes são o coração do projeto. Cada um resolve um único problema e não possui dependência do framework.

  • HttpFoundation — classes Request e Response orientadas a objetos.
  • Routing — mapeia URLs para controllers usando atributos, YAML ou PHP.
  • Console — constrói ferramentas de linha de comando com argumentos e opções.
  • Mailer — envia e-mails através de transports e mensagens com templates.
  • Serializer — converte objetos para JSON, XML e vice-versa.
  • EventDispatcher — desacopla o código com eventos e listeners.

Você pode instalar qualquer um deles diretamente:

composer require symfony/http-foundation
use Symfony\Component\HttpFoundation\Request;

$request = Request::createFromGlobals();
$page = $request->query->getInt('page', 1);

Essa portabilidade é o motivo pelo qual os componentes do Symfony aparecem em todos os lugares, até mesmo em projetos que jamais adotariam o framework completo.

O kernel HTTP e controllers

Em uma aplicação completa, cada requisição flui através do HttpKernel. Ele dispara um evento, faz a correspondência de uma rota, chama um controller e transforma o Response retornado em saída. Os controllers estendem AbstractController para obter helpers convenientes.

class BlogController extends AbstractController
{
    #[Route('/blog/{slug}', name: 'blog_show')]
    public function show(string $slug, PostRepository $posts): Response
    {
        $post = $posts->findOneBy(['slug' => $slug]);

        if (!$post) {
            throw $this->createNotFoundException('Post not found');
        }

        return $this->render('blog/show.html.twig', ['post' => $post]);
    }
}

Um controller deve retornar um Response. $this->render() constrói um a partir de um template Twig, $this->json() retorna JSON e $this->redirectToRoute() retorna um redirecionamento. Como o objeto de resposta é explícito, os testes e o middleware são simples.

Templates Twig estendem um layout base e preenchem blocos, e a saída é escapada, a menos que você opte por desativar isso:

{# templates/blog/show.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <article>
        <h1>{{ post.title }}</h1>
        <p>{{ post.publishedAt|date('F j, Y') }}</p>
        {{ post.body|raw }}
    </article>
{% endblock %}

Roteamento por atributos

As rotas são declaradas ao lado da action que as manipula, utilizando atributos do PHP 8.

#[Route('/blog', name: 'blog_index', methods: ['GET'])]
#[Route('/blog/{slug}', name: 'blog_show', methods: ['GET'])]

O roteamento também pode ficar em config/routes.yaml quando você prefere mantê-lo separado. Atributos são o padrão no Symfony moderno porque a rota e o método permanecem juntos. Verifique o que está registrado a qualquer momento com:

php bin/console debug:router

O service container e o autowiring

Quase tudo no Symfony é um service, e o container os constrói e conecta. Com o autowiring habilitado, você só precisa adicionar o type-hint no construtor.

class PostPublisher
{
    public function __construct(
        private EntityManagerInterface $em,
        private MailerInterface $mailer,
    ) {}
}

config/services.yaml instrui o container a realizar o autowire de suas classes:

services:
    _defaults:
        autowire: true
        autoconfigure: true

    App\:
        resource: '../src/'
        exclude:
            - '../src/Entity/'
            - '../src/Kernel.php'

Quando existirem duas implementações de uma interface, vincule a correta explicitamente. O container é compilado em PHP puro para produção, e é por isso que ele é rápido, apesar de ser tão dinâmico para escrever.

Bundles e receitas do Flex

Um bundle empacota funcionalidades em uma unidade distribuível. Funcionalidades de terceiros — Doctrine, segurança, mailer, painéis administrativos — chegam como um bundle, e o próprio framework é composto por bundles principais.

Instalar um deles requer apenas um comando:

composer require symfony/orm-pack

O Symfony Flex é o plugin do Composer que torna esse processo agradável. Quando um pacote possui uma receita, o Flex cria os arquivos de configuração, registra o bundle e, frequentemente, adiciona variáveis de ambiente ou um serviço docker-compose. É por isso que as aplicações Symfony modernas possuem configurações pequenas e explícitas, em vez de páginas de boilerplate.

Doctrine ORM

O Doctrine é a camada de persistência padrão. As entidades são classes PHP simples anotadas com atributos de mapeamento, e os repositórios encapsulam as queries.

#[ORM\Entity(repositoryClass: PostRepository::class)]
class Post
{
    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private string $title;

    #[ORM\Column(type: 'text')]
    private string $body;

    #[ORM\Column(type: 'datetime_immutable', nullable: true)]
    private ?\DateTimeImmutable $publishedAt = null;
}

As queries geralmente são expressas através da API do repositório ou DQL, em vez de strings SQL:

$latest = $posts->findBy([], ['publishedAt' => 'DESC'], limit: 10);

As alterações de schema são gerenciadas com o Doctrine Migrations, que compara o seu mapeamento com o banco de dados e gera arquivos de migração versionados que você pode revisar antes de executar.

Configuração e ambientes

O Symfony separa a configuração do código e a aplica por ambiente. APP_ENV seleciona o ambiente, e os arquivos sob config/ são sobrepostos uns aos outros.

  • .env contém os padrões locais e variáveis de ambiente.
  • config/packages/ configura os bundles para todos os ambientes.
  • config/packages/dev/ e config/packages/prod/ fazem a sobrescrita por ambiente.
  • config/routes.yaml e config/services.yaml são as configurações próprias do app.

O ambiente dev habilita o profiler e ferramentas de debug, test utiliza um banco de dados separado, e prod compila tudo para maior performance. Limpar o cache após alterações de configuração é uma parte normal do fluxo de trabalho:

php bin/console cache:clear

Messenger e processamento assíncrono

O componente Messenger retira o processamento de dentro da requisição. Você despacha uma mensagem para um bus e um handler a processa, seja imediatamente ou em um worker.

final class UserRegistered
{
    public function __construct(public readonly int $userId) {}
}

#[AsMessageHandler]
final class SendWelcomeEmail
{
    public function __invoke(UserRegistered $message): void
    {
        // send the email here
    }
}

Despache de qualquer lugar e consuma a fila em um processo separado:

$bus->dispatch(new UserRegistered($user->getId()));
php bin/console messenger:consume async

Os transports podem ser Doctrine, Redis, AMQP ou um serviço de terceiros, e mensagens que falharam podem ser repetidas ou armazenadas, tornando o processamento em background uma prioridade nativa do sistema.

Testando com PHPUnit

O Symfony já vem com o PHPUnit e uma classe base WebTestCase que inicializa o kernel e realiza requisições HTTP reais.

class BlogControllerTest extends WebTestCase
{
    public function testShowPost(): void
    {
        $client = static::createClient();
        $client->request('GET', '/blog/hello-world');

        $this->assertResponseIsSuccessful();
        $this->assertSelectorTextContains('h1', 'Hello world');
    }
}

Como os serviços são injetados, os testes unitários podem substituir uma dependência por um stub ou um mock sem precisar mexer no container. Deixe os testes de integração para a camada HTTP e os testes unitários para os serviços que contêm as regras de negócio.

Melhores práticas

  • Prefira a injeção via construtor em vez de buscar serviços diretamente do container.
  • Mantenha os controllers enxutos; mova a lógica para os services.
  • Use repositories para consultas e mantenha o SQL fora dos controllers.
  • Declare as rotas como atributos ao lado da action que elas chamam.
  • Deixe o Flex gerenciar a configuração do bundle em vez de escrever boilerplate.
  • Separe a configuração por ambiente e mantenha segredos em variáveis de ambiente.
  • Coloque tarefas demoradas no Messenger em vez de processá-las durante a requisição.
  • Analise o profiler quando algo estiver lento ou inesperado.

Erros comuns

  • Chamar $container->get() em vez de injetar dependências.
  • Colocar lógica de negócio em controllers e entities.
  • Esquecer de registrar ou vincular uma interface e depois questionar o que o container resolveu.
  • Commitar segredos do .env em vez de mantê-los fora do controle de versão.
  • Editar migrations geradas após elas terem sido executadas.
  • Misturar estilos de configuração aleatoriamente entre YAML, XML e PHP.
  • Ignorar avisos de depreciação até a próxima atualização major.

Próximos passos

O Symfony oferece os componentes e a disciplina necessários para construir sistemas duradouros, e suas ideias estão presentes em diversos frameworks do ecossistema. Leia o guia do Laravel para ver esses componentes sendo utilizados para o desenvolvimento rápido de aplicações, ou compare essa filosofia com a abordagem minimalista do Express. Para projetar e evoluir as APIs que você expõe, continue com REST e versionamento de API.

Obtendo um serviço

Deixe o container injetar o que você precisa. Extrair serviços manualmente do container esconde dependências e torna a classe mais difícil de testar.

Preferir
class NewsletterService
{
    public function __construct(
        private MailerInterface $mailer,
    ) {}
}
Evitar
class NewsletterService
{
    public function send(): void
    {
        $mailer = $this->container->get('mailer');
        $mailer->send(/* ... */);
    }
}

Buscando uma entidade

Repositórios expressam a intenção e retornam objetos. SQL puro em um controller acopla a camada HTTP ao schema e ignora o mapeamento do Doctrine.

Preferir
$post = $posts->findOneBy(['slug' => $slug]);
if (!$post) {
    throw $this->createNotFoundException();
}
Evitar
$conn = $this->getDoctrine()->getConnection();
$post = $conn->fetchAssociative(
    'SELECT * FROM posts WHERE slug = ?',
    [$slug],
);

Trade-offs

O Symfony é o framework PHP certo?

O Symfony troca a gratificação instantânea por estrutura, estabilidade e reuso. Essa troca compensa principalmente em sistemas complexos e de longa duração.

Strengths

  • Componentes reutilizáveis

    Como o framework é montado a partir de bibliotecas, você pode levar as partes necessárias para qualquer projeto, e já as conhecerá ao trabalhar com Drupal ou Laravel.

  • Estabilidade e atualizações previsíveis

    Versões LTS, depreciações documentadas e uma política rigorosa de retrocompatibilidade significam que as atualizações são trabalhos planejados, não reescritas.

  • Construído para domínios complexos

    O container, event dispatcher, Messenger, workflow e componentes de formulário lidam com o tipo de aplicação que cresce além de uma stack mais simples.

Trade-offs

  • Mais conceitos iniciais

    Kernel, container, bundles, ambientes e recipes são muita coisa para aprender antes de escrever uma funcionalidade. Reserve tempo para entender o modelo mental.

  • Forte em configuração

    Mesmo com o Flex, o Symfony solicita que você configure serviços, roteamento e pacotes explicitamente, o que é poderoso, porém verboso.

  • Prototipagem mais lenta

    Para um app CRUD pequeno, um framework 'batteries-included' leva você a uma tela funcional mais rápido. A estrutura do Symfony começa a vencer conforme o domínio cresce.

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender Symfony?

Nosso tutorial interativo te guia por Symfony passo a passo — com quizzes e codigo real que voce pode executar no navegador.