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.xml e 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érioPluginObserverPreference sobre classe do core
O que alteraEntrada, saída ou execução de um método públicoNada no método: executa código quando o evento aconteceA classe inteira
Onde não alcançaMétodo final, não público ou estático, construtor e virtual typeOnde o core não dispara eventoAlcança também métodos protegidos, por herança
Dois módulos no mesmo pontoConvivem, na ordem do sortOrderConvivem, sem ordem garantidaNa mesma área, só uma vale
Risco no upgradeQuebra se o método interceptado mudarPara de rodar se o evento deixar de ser disparadoA versão modificada deixa de receber as correções do core nos métodos reescritos
Escolha certa quandoPrecisa mudar um método específicoPrecisa reagir a um acontecimento sem alterar o valor recebidoPlugin 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' frontend

Como 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 (frontend ou adminhtml).
  • A cada upgrade, setup:di:compile em 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

  1. Plugins (interceptors) (Adobe Commerce Developer)
  2. The di.xml file (preferences) (Adobe Commerce Developer)
  3. Observers best practices (Adobe Commerce Developer)
  4. Technical guidelines (Adobe Commerce Developer)
  5. Commerce on-premises: command-line reference (dev:di:info) (Adobe Experience League)
  6. Code compiler (setup:di:compile) (Adobe Experience League)

Outros artigos

Ver todos os artigos

Precisa de um orçamento? Ficarei feliz em ajudar. Clique aqui