[Qualidade de código] Como o PHPMD pode ajudar a tornar seu código melhor
Da série "Qualidade de código", hoje vou apresentar como a análise estática PHPMD pode lhe ajudar
Afinal, o que é a série qualidade de código?
É uma série de artigos que dão dicas de como melhorar a qualidade do seu código, com dicas teóricas, dicas de ferramentas para facilitar nosso dia a dia como desenvolvedor. Mas focado em desenvolvimento em PHP. Essa série está sendo uma continuação do primeiro artigo publicado por mim, pode ser encontrado aqui: "Como mensurar a qualidade de código php"
O que é PHPMD?
PHPMD é uma ferramenta de análise estática, com essa ferramenta é possível validar alguns pontos como:
- Visualização de métodos não utilizados;
- Visualização de propriedades não utilizadas;
- Visualização de parâmetros não utilizados;
- Visualização de possíveis bugs;
- Verificação de complexidade do código;
Com essas validações do PHPMD é possível criar um código limpo e de fácil entendimento.
Para a demonstração iniciei um código usando docker com Lumen, para isso tenho dois containers:
- api.estudo-lumen.dev - Onde roda o nginx;
- app.estudo-lumen.dev - Onde roda o PHP com composer;
Caso esteja utilizando a estrutura com docker, acesse seu container com o PHP, caso não esteja utilizando docker, apenas entre com o terminal em seu projeto e vamos executar os seguintes comandos:
composer require --dev phpmd/phpmd
Após ser instalado o phpmd e suas dependências, a utilização do phpmd é simples, temos que chamar o phpmd com 3 argumentos:
$1 pasta dos códigos -> temos que informar qual arquivo queremos que seja analisado, caso queira que todo o código seja analisado, apenas insira ".", mas caso queira um arquivo específico insira o caminho "app/Services/ServicoQualquer.php".
$2 retorno dos erros -> é necessário informar qual o tipo do retorno dos problemas, temos 3 tipos para ser utilizado, xml, text, html, json, ansi, github, sarif, checkstyle.
$3 regras para verificar -> por último temos que passar quais regras gostaríamos que fosse verificado, atualmente temos disponíveis:
- Cleancode -> Aplica regras que impõem um código limpo;
- Code size -> Aplica regras verificando o tamanho do código;
- Controversial -> Aplica regras analisando divergências no código;
- Design -> Aplica regras analisando o design do código;
- Naming -> Aplica regras analisando o tamanho de variáveis, métodos;
- Unused code -> Aplica regras analisando códigos que não são utilizados;
Caso queira verificar o que é considerado em cada regra, no site oficial tem a explicação de todas as regras.
Para testarmos criei um método no controller chamado teste
e junto uma variável chamada $teste
ficando dessa maneira:
class Controller extends BaseController
{
public function teste()
{
$teste = "";
}
}
Vamos verificar esta classe utilizando esse comando:
./vendor/bin/phpmd app/Http/Controllers/Controller.php text cleancode,codesize,controversial,design,naming,unusedcode
Ou seja, instanciamos o phpmd, o arquivo a ser verificado Controller.php
, o tipo de retorno text
e as regras que desejamos verificar. Ao executarmos o comando, temos como retorno o seguinte texto:
app/Http/Controllers/Controller.php:11 UnusedLocalVariable Avoid unused local variables such as '$teste'.
Foi encontrado um "erro" no arquivo app/Http/Controllers/Controller.php
, na linha 11, o tipo de erro é UnusedLocalVariable, ou seja, temos uma variável não utilizada na linha 11 do arquivo Controller.php
.
Vamos "arrumar" o ocorrido e realizar novamente a validação, ficando dessa maneira:
class Controller extends BaseController
{
public function teste()
{
$teste = "Olá mundo!";
return $teste;
}
}
Executando o mesmo comando executado anteriormente, o nosso console fica vazio, ou seja, as validações não encontraram nenhum ponto de atenção.
Mas caso alguma parte do código, seja realmente necessário para o desenvolvimento do código e infere em alguma verificação, como por exemplo, if else
:
class Controller extends BaseController
{
public function teste()
{
$teste = "Olá mundo!";
if ($teste == null) {
$teste = 1;
} else {
$teste = 0;
}
return $teste;
}
}
Ao realizarmos a validação do PHPMD é retornado o seguinte erro:
/app/Http/Controllers/Controller.php:15 ElseExpression The method teste uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.
Mas não podemos retirá-lo do código e não temos ideia de como refatorar, então podemos apenas pedir para o PHPMD ignorar algumas regras e temos duas maneiras de fazer, a primeira é uma maneira mais "bruta", pois ignora todos os tipo de regras, para isto temos que adicionar uma annotation
no método:
/**
* @return int
* @SuppressWarnings("PHPMD")
*/
public function teste()
{
$teste = "Olá mundo!";
if ($teste == null) {
$teste = 1;
} else {
$teste = 0;
}
return $teste;
}
Mas desta maneira é possível que tenha alguma outra regra que seja infringida e não foi percebida. Para isto vamos ignorar somente a regra ElseExpression
, ficando desta maneira:
/**
* @return int
* @SuppressWarnings("PHPMD.ElseExpression")
*/
public function teste()
{
$teste = "Olá mundo!";
if ($teste == null) {
$teste = 1;
} else {
$teste = 0;
}
return $teste;
}
Para ignorar qualquer erro de regra do PHPMD, basta verificarmos a regra mostrada no console e colocar após o PHPMD na annotation.
Mas caso não goste das regras pré-estabelecidas pela biblioteca e queira criar suas próprias regras, também é possível, basta criarmos um arquivo na raiz do projeto chamado rulesets.xml
com esta estrutura:
<?xml version="1.0"?>
<ruleset name="PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
Seu xml com suas regras definidas.
</description>
<rule ref="rulesets/codesize.xml" />
<rule ref="rulesets/cleancode.xml" />
<rule ref="rulesets/controversial.xml" />
<rule ref="rulesets/design.xml" />
<rule ref="rulesets/naming.xml" />
<rule ref="rulesets/unusedcode.xml" />
</ruleset>
Na estrutura acima temos todas as regras setadas, mas para o teste que faremos, vamos apenas utilizar uma, ficando desta maneira:
<?xml version="1.0"?>
<ruleset name="PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
Seu xml com suas regras definidas.
</description>
<rule ref="codesize.xml" />
</ruleset>
Vamos criar um novo arquivo na raiz denominado codesize.xml
, onde será setado as regras, o arquivo padrão está localizado aqui.
Para o teste, criei um código cheio de if
, assim a nossa verificação cairá na regra de CyclomaticComplexity
, podemos ver abaixo:
public function teste()
{
$teste = "Olá mundo!";
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
if ($teste == null) {
echo "dd";
}
}
}
}
}
}
}
}
}
}
}
}
}
}
return $teste;
}
Quando temos um arquivo personalizado com as regras, ao chamar o teste, ao invés de chamar o conjunto de regras padrões, temos que chamar o arquivo criado, então fica desta maneira:
./vendor/bin/phpmd app/Http/Controllers/Controller.php text rulesets.xml
Temos como retorno da verificação :
/app/Http/Controllers/Controller.php:12 CyclomaticComplexity The method teste() has a Cyclomatic Complexity of 15. The configured cyclomatic complexity threshold is 10.
Mas como estamos em nosso conjunto de regras, podemos personalizar a regra, podendo assim alterar o complexidade padrão, de 10 para 16 por exemplo, para isto voltamos para o arquivo codesize.xml
.
Neste arquivo temos diversas regras, podemos localizar pelo name das regras, em nosso caso estamos procurando a regra denominada CyclomaticComplexity
, então podemos procurar por este nome, ao encontrar temos dentro de properties as propriedades de verificação, no caso particular temos o reportLevel que está com valor de 10, mas estamos com a complexidade no nível 15, então ao alterar o valor de 10 para 16 e executarmos novamente, temos como resultado a não visualização do aviso.
<property name="reportLevel" description="The Cyclomatic Complexity reporting threshold" value="16"/>
Chegamos ao fim deste artigo, passamos por todos os pontos básicos de utilização do PHPMD, bora colocar essa etapa na pipeline dos devs?