Uma narrativa do uso do Composer em um plugin do WordPress
Publicados: 2015-07-06
Esta peça foi contribuída pelo autor convidado Peter Suhm. Peter é um desenvolvedor web da Terra dos Dinamarqueses. Ele é o criador do WP Pusher e um grande viciado em viagens, trazendo seu trabalho junto com ele.
Outro dia postei um aviso sobre o uso do Composer em plugins do WordPress no blog do WP Pusher. Este post chamou muita atenção e sinto a necessidade de esclarecer alguns pontos que não ficaram claros para todos. O artigo também foi um pouco pesado na parte técnica, então neste post vou tentar deixar meu ponto principal mais claro usando uma narrativa simples para ilustrá-lo.
Uma narrativa

Vamos imaginar por um tempo que você e eu somos autores de plugins. Ambos temos uma ótima ideia para um plugin que desejamos distribuir via WordPress.org. Queremos incluir alguns recursos premium em nossos plugins que os usuários da versão gratuita podem desbloquear digitando uma chave de licença.
Precisamos de algum código que possa lidar com esse processo. Nós dois percebemos que esse problema provavelmente já foi resolvido por outra pessoa. Nenhum de nós é fã de reinventar a roda, então vamos ao Packagist e digitamos “gerenciador de licenças”. Parece que nossa suposição foi justificada. Yoast já tem um pacote que pode lidar com isso. Nós dois decidimos fazer um rápido composer require yoast/license-manager . Mole-mole. Agora podemos seguir em frente para trabalhar em algo que realmente importa - os recursos principais de nossos respectivos plugins.
Avançando rapidamente, pronto para liberar seu plugin, você percebe algo: seu usuário não necessariamente tem o Composer à mão ao instalar seu plugin do WordPress.org, então como eles vão obter o código para o gerenciador de licenças? Essa situação é um pouco irritante, porque a única solução que você realmente vê é apenas enviar todo o diretório de vendor gerado pelo Composer para o seu plugin e enviá-lo para o WordPress.org. Você sabe que não é assim que o Composer deve funcionar, mas tanto faz. Você realmente não tem outras opções.
Enquanto isso, cheguei à mesma conclusão com meu plugin. Basta incluir o código do gerenciador de licenças e pronto.
Avançando mais uma vez, ambos os nossos plugins agora estão no repositório WordPress.org e, de vez em quando, alguém decide atualizar para nossas versões premium. Tudo parece estar bem e nós dois estamos gratos por podermos usar o código que o Yoast generosamente abriu e não tivemos que reinventar a roda.
Um dia, você recebe um e-mail estranho. Um cliente está experimentando um comportamento muito estranho ao tentar desbloquear seus recursos premium. Não faz sentido para você, porque ninguém mais relatou isso. Depois de horas de depuração, você finalmente pede ao seu cliente para desativar todo o resto, exceto seu plugin, e então: Funciona! Hum. Seu plugin parece de alguma forma ser incompatível com outro plugin. Meu plug-in.
Você percebe isso depois de horas passando pelo código-fonte de todos os outros plugins que o cliente instalou. Quando você percebe que nós dois usamos o gerenciador de licenças, uma campainha toca. Pode ser realmente isso? Em caso afirmativo, como não há fatal errors: cannot redeclare class foi causada pelo PHP?
Uma semana antes, eu havia transferido a versão necessária do gerenciador de licenças no meu plugin para a versão mais recente, que incluía algumas alterações (fictícias) de última hora. Após ainda mais depuração e var_dump() ', você percebe que minha versão do gerenciador de licenças também é a versão carregada pelo PHP em seu plugin. Você acha isso muito estranho porque você exigiu especificamente outra versão do gerenciador de licenças com o Composer. Você realmente não sabe o que fazer sobre isso.
Porque realmente não há muito que você possa fazer sobre isso.
O que aconteceu aqui?
Agora que todos já vimos o problema, vamos parar um pouco para analisar o que realmente aconteceu na narrativa. Em primeiro lugar, por que o PHP não causou um erro fatal quando duas classes obviamente tinham o mesmo nome que nós dois incluímos o gerenciador de licenças?
A razão para isso é que usamos um autoloader gerado pelo Composer. Este autoloader verifica a estrutura de diretórios de nossas dependências e adiciona todas as classes ao autoloader. Se uma classe já foi adicionada, o Composer irá ignorá-la. Silenciosamente. Eu escrevi um pequeno exemplo de código se você quiser ver por si mesmo. Está no GitHub.
Por que minha versão do gerenciador de licenças foi incluída antes da sua?
Isso aconteceu porque meu plugin tinha um nome que fazia com que ele fosse carregado antes do seu. Talvez, no futuro, todos nós nomeemos nossos plugins “Aaaaaa My Plugin” para serem carregados primeiro!

Então, para resumir, o principal problema aqui é que não saberemos qual versão de nossas dependências está disponível para nós em qual momento. Simplesmente depende de fatores que não podemos controlar totalmente como desenvolvedores de plugins.
Este é um problema específico do Composer?
Não. Realmente não é. O WordPress não tem como lidar com código de terceiros em plugins ou temas. Ai que fica o problema. A razão pela qual estou falando do Composer é que ele está ganhando muita força nos dias de hoje. Se os desenvolvedores do WordPress quiserem usar o Composer em plugins lançados via WordPress.org, isso precisa ser resolvido de alguma forma. Caso contrário, veremos um verdadeiro caos quando todos os plugins começarem a ser incompatíveis entre si por usarem versões diferentes. Bem-vindo ao inferno de depuração.
O que podemos fazer sobre isso?
Alguém que realmente se preocupou com isso e trabalhou duro para encontrar uma possível solução é Coen Jacobs. Decidi entrar em contato com Coen e perguntar se ele acha que há algo que possamos fazer sobre isso.
Muitos desenvolvedores já estão incluindo código de terceiros em seus plugins. Isto é realmente um problema?
Sim, isso já é um problema no ecossistema de plugins. Ficará ainda pior quando mais pessoas descobrirem que é uma boa ideia colocar funcionalidades comuns em pacotes separados. Esses pacotes podem ser agrupados com vários plugins e o problema aparecerá cada vez mais. Eu tenho falado com alguns desenvolvedores que já passaram pelo inferno da depuração tentando descobrir o que está causando esse problema.
Seguindo em frente, você sugeriria que os desenvolvedores parassem de incluir código de terceiros em seus plugins?
Estou um pouco dividido sobre este assunto. Não faz sentido, do ponto de vista dos desenvolvedores, dizer às pessoas para parar de agrupar pacotes compartilhados em seus plugins. Por outro lado, todos querem a melhor experiência de usuário possível para seus usuários. É uma decisão difícil de tomar com certeza.
Neste ponto, quero impulsionar o desenvolvimento relacionado ao WordPress. Quero compartilhar bibliotecas e usar bibliotecas compartilhadas por outras pessoas. Ninguém deveria estar reinventando a roda repetidamente. Então eu correria o risco de me deparar com problemas como esse, resolvendo os problemas à medida que eles aparecem.
Isso também significa que farei o meu melhor para encontrar uma solução de longo prazo para esse problema. Mais pessoas começarão a usar o Composer, mais pessoas agruparão bibliotecas com seus plugins. Esse problema aparecerá com mais frequência, então é hora de corrigi-lo.
O que os desenvolvedores de plugins podem fazer para evitar esse problema?
Existe uma solução alternativa que eu já vi algumas pessoas usarem. Basicamente se resume a mover sua dependência para o namespace do seu plugin. Danny van Kooten fez isso para um de seus plugins. Isso não é ideal no entanto. Toda vez que ele atualiza suas dependências, ele precisa passar por todos os arquivos e alterar os namespaces novamente. Agora, esta não é uma tarefa tão grande para uma biblioteca relativamente pequena como a Pimple, mas um empreendimento enorme para bibliotecas maiores.
Isso só pode ser feito com namespaces, então você terá que fazer seu plugin exigir PHP 5.3+ também. Não vou mentir, acho que todo plugin deveria começar a fazer isso mais cedo ou mais tarde, mas definitivamente é algo que você precisa considerar quando decidir fazer isso.
Qual seria a solução ideal, se houver alguma?
A situação ideal seria usar algum tipo de gerenciador de dependências. Claro que existe o Composer, o gerenciador de dependências mais usado. O Composer é muito difícil, se não impossível, de usar para a grande maioria dos usuários do WordPress. Afinal, é uma ferramenta de desenvolvedor.
O WordPress deve facilitar isso para seus usuários finais, enquanto ainda permite que os desenvolvedores utilizem praticamente qualquer pacote que desejarem. Pensando nisso, comecei a montar o plugin WordPress Composer Installer, que faz todo o trabalho duro do Composer enquanto as pessoas instalam plugins como sempre fizeram. Assim que eu conseguir terminar isso, vou integrá-lo corretamente em todo o fluxo do instalador de plugins.
Agora, talvez um dia, isso possa ser integrado ao núcleo do WordPress. Tem um longo caminho a percorrer, mas a prova de conceito já funciona.
Conclusão
Se você leu até aqui, antes de mais nada: obrigado. Em segundo lugar, espero que agora você veja como isso é algo que eventualmente se tornará um problema. Nossa situação atual é muito frustrante, porque simplesmente não temos as ferramentas de que precisamos. Ainda assim, acho importante continuarmos falando sobre isso e garantir que todos nós, como desenvolvedores do WordPress, entendamos os possíveis problemas causados por dependências conflitantes de terceiros em nosso código.
Finalmente, quero mencionar mais uma vez que este não é um problema do Composer. É um problema do WordPress.
