Recentemente tenho ajudado um amigo a entender um código e a descobrir como modificá-lo para funcionar bem com chamadas assíncronas ao backend. Um bônus seria conseguir escrevê-lo de um jeito mais modular e reutilizável.

O código é um plugin de WordPress escrito com uma abordagem bem legada: lógica de negócio e de frontend misturadas num lugar só. Manipulação de dados feita no meio do código de template, e coisas do tipo.

Basicamente, o que você via em sites PHP no começo dos anos 2000, antes de todas as incríveis adições de OOP à linguagem e de um monte de frameworks maduros.

O caso em que eu estava trabalhando hoje era o seguinte: você tem uma tabela que mostra um monte de registros. Precisávamos adicionar vários filtros à tabela e fazê-la funcionar via AJAX, para atualizar a interface rapidamente, sem recarregar a página inteira do Admin do WordPress.

Filtrar os dados foi fácil: um array_filter inline rapidinho para filtrar os dados antes de passá-los ao código do template (para manter o mesmo estilo de código, isso também ficou no arquivo de template 😇).

O problema apareceu quando começamos a trabalhar para tornar a tabela renderizável via AJAX.

Ela está no meio de um monte de outros códigos de template e de negócio. Se quiséssemos limitar a saída via AJAX só à tabela, só tínhamos algumas maneiras de fazer isso.

A primeira seria envolver o HTML antes e depois da tabela em ifs ENORMES para garantir que ele não fosse renderizado.

Outra seria extrair o template para um arquivo separado e incluí-lo na ação de AJAX que definiríamos no código do plugin.

Funções anônimas para o resgate!

Pensando em como lidar com isso da maneira mais simples possível, tentei definir uma função PHP normal que conteria o código da tabela, mas havia um problema.

O código roda dentro de um método de uma classe. Há referências a $this no template da tabela. Se não queremos mudar muito o código, teríamos que passar $this como argumento da função. Pois é, isso não funciona, já que você não pode passar $this como parâmetro 🤷‍♂️.

Fiquei meio decepcionado por termos que reescrever um monte de coisas no template, e havia bastantes referências com as quais precisávamos tomar cuidado para que tudo continuasse funcionando.

Então lembrei que o site não roda em PHP 5.2, mas em PHP 7, e que funções anônimas seriam suportadas.

E elas têm um recurso bem prático, em que você define quais variáveis do escopo de quem chama serão passadas para a função quando ela for chamada. Por exemplo:

$table_function = function() use ( $pages, $current_page, $items ) {
    // ... Table render code
}

Isso permite referenciar diretamente $pages ou $items no corpo da função.

O recurso incrível aqui é que você também pode passar $this como uma variável no escopo da função!

Agora conseguimos extrair totalmente o código de renderização da tabela para uma função separada, que podemos chamar isoladamente durante a chamada AJAX!

Claro que é preciso ter muito cuidado com as variáveis usadas dentro do corpo da função, pois elas precisam estar definidas, então atenção a onde a função de AJAX pode ser chamada.

Para nós, isso significa que vamos adicionar uma pequena ação na classe principal que ainda vai dar require no arquivo, mas teremos mais controle para desativar todas as outras saídas que aconteceriam.