O que é plugin, observer e preference no Magento 2
Os três são formas de mudar o comportamento do Magento sem editar o código dele em vendor/, que o Composer sobrescreve na atualização. A diferença está em quanto do core cada um toca:
- Plugin intercepta um método público de uma classe e roda antes (before), depois (after) ou no lugar dele (around). É declarado no
di.xml. - Observer reage a um evento que o Magento dispara, como um pedido salvo. É declarado no
events.xmle só funciona onde o core dispara o evento. - Preference diz ao Magento para entregar outra classe no lugar da original, em todo ponto que pedir por ela. Também fica no
di.xml.
A preference tem dois usos bem diferentes. Ligar uma interface à classe que a implementa é o uso normal, e o próprio core faz isso o tempo todo. Trocar uma classe concreta do core por uma versão modificada é o uso que cobra caro depois.
Plugin, preference ou observer: comparação com critério
| Critério | Plugin | Observer | Preference sobre classe do core |
|---|---|---|---|
| O que altera | Entrada, saída ou execução de um método público | Nada no método: executa código quando o evento acontece | A classe inteira |
| Onde não alcança | Método final, não público ou estático, construtor e virtual type | Onde o core não dispara evento | Alcança também métodos protegidos, por herança |
| Dois módulos no mesmo ponto | Convivem, na ordem do sortOrder | Convivem, sem ordem garantida | Na mesma área, só uma vale |
| Risco no upgrade | Quebra se o método interceptado mudar | Para de rodar se o evento deixar de ser disparado | A versão modificada deixa de receber as correções do core nos métodos reescritos |
| Escolha certa quando | Precisa mudar um método específico | Precisa reagir a um acontecimento sem alterar o valor recebido | Plugin e observer não alcançam, e o motivo está escrito |
Duas linhas da tabela vêm das diretrizes técnicas da Adobe: a que proíbe o observer de modificar os valores passados ao evento (para isso, plugin) e a que pede composição em vez de herança, que é justamente o que a preference sobre classe concreta deixa de lado.
Por que preference dá problema no upgrade
Quando o dev cria uma preference sobre uma classe concreta do core, a classe nova herda da original e reescreve um ou mais métodos. A partir daí, esses métodos na sua loja são a versão do dev. Se a Adobe corrigir um defeito naquele método numa versão nova, a correção não chega à sua loja, porque o Magento continua entregando a classe do dev.
Se a classe original ganhar uma dependência nova no construtor, a classe herdada pode quebrar. O setup:di:compile valida os construtores e interrompe a compilação com erros como Missed required argument ... in parent::__construct call, e é por isso que ele precisa rodar em staging antes de qualquer upgrade chegar à produção.
O conflito entre extensões segue a mesma lógica. Duas extensões com preference sobre a mesma classe, na mesma área, não somam: o Magento só entrega uma classe, e a outra extensão perde o efeito. Para o lojista, isso aparece como "a extensão X parou de funcionar depois que instalamos a Y".
Nada disso quer dizer que toda preference é erro, e não existe número "bom" de preferences para mirar. O que importa é quais classes elas trocam e se existe motivo escrito para cada uma.
Plugin around pesa no desempenho?
Pode pesar. A documentação da Adobe pede para evitar plugin around quando ele não é necessário, porque aumenta a pilha de chamadas e afeta o desempenho, e a diretriz técnica reserva o around para quando o comportamento original precisa ser substituído. Para só ajustar argumento ou resultado, before e after resolvem.
O custo depende de onde o plugin está. Um around num método chamado muitas vezes por página, como um cálculo exibido em cada produto de uma listagem, é bem diferente de um around no salvamento de um pedido. Não peça ao dev para zerar arounds; peça o motivo de cada um.
Como contar preferences e plugins do projeto
Três verificações que você pode pedir ao dev ou a alguém de confiança, na raiz da loja:
# 1. preferences que trocam classe, e não interface
grep -rn --include=di.xml '<preference' app/code | grep -v 'Interface"'
# 2. plugins declarados e métodos around
grep -rn --include=di.xml '<plugin' app/code | wc -l
grep -rn --include='*.php' 'public function around' app/code | wc -l
# 3. quem mexe numa classe específica
bin/magento dev:di:info 'Magento\Catalog\Model\Product'
bin/magento dev:di:info 'Magento\Catalog\Model\Product' frontendComo ler o primeiro: o filtro esconde as preferences cujo alvo termina em Interface, que são o uso normal. Testei o mesmo comando no módulo de catálogo do Magento 2.4.8-p4: ele declara 105 preferences, e só 2 passam pelo filtro. Cada linha que sobrar no seu projeto merece justificativa. Módulos instalados via Composer ficam em vendor/, então rode também na pasta de cada fornecedor.
Como ler o segundo: não existe total certo. O número serve para perguntar por que cada around existe. A contagem de plugins inclui os desligados com disabled="true".
Como ler o terceiro: o dev:di:info mostra a linha Preference: (se aparecer outra classe, alguém trocou a original) e as tabelas Plugins: e Plugins for the Preference:, com as colunas Plugin, Method e Type. Sem o segundo argumento, ele olha só a configuração global; passe frontend ou adminhtml para ver o que vale na vitrine ou no admin.
Customização que não quebra na atualização: o que combinar com o dev
- Plugin before ou after como padrão; around só com motivo escrito no pull request.
- Preference sobre classe do core só quando plugin e observer não alcançam, com a justificativa no README do módulo.
- Observer que não altera o objeto recebido e fica declarado na área certa (
frontendouadminhtml). - A cada upgrade,
setup:di:compileem staging antes da produção. - Lista das preferences e plugins do projeto atualizada em cada entrega.
Esses itens também servem na contratação: as perguntas de entrevista técnica para dev Magento começam justamente por plugin, preference e observer. E se a sua loja tem customização pesada, é o perfil de backend descrito em o que faz um programador Magento que vai cuidar disso.
Perguntas frequentes
Usar preference no Magento é sempre errado?
Não. Ligar uma interface à implementação é o uso normal, e o próprio core faz isso mais de mil vezes no 2.4.8-p4. O cuidado é com preference que troca uma classe concreta do core, porque ela deixa de receber correções e conflita com outras extensões que mexem na mesma classe.
Plugin deixa a loja Magento lenta?
A documentação da Adobe aponta o around como o tipo que aumenta a pilha de chamadas e afeta o desempenho, e pede para evitá-lo quando não é necessário. Em qualquer tipo de plugin, o impacto depende de quantas vezes o método interceptado roda por página.
Dá para trocar uma preference por plugin depois?
Dá, quando o que a preference altera é um método público: o dev reescreve a mudança como plugin before, after ou around e remove a preference. Se a alteração depende de método protegido ou do construtor, o plugin não alcança e a troca exige repensar a solução.
Fontes oficiais
- Plugins (interceptors) (Adobe Commerce Developer)
- The di.xml file (preferences) (Adobe Commerce Developer)
- Observers best practices (Adobe Commerce Developer)
- Technical guidelines (Adobe Commerce Developer)
- Commerce on-premises: command-line reference (dev:di:info) (Adobe Experience League)
- Code compiler (setup:di:compile) (Adobe Experience League)