Padrão PSR-2 de desenvolvimento PHP - Ampliando a capacidade de comunicação entre diferentes códigos PHP Artigo

Conheça os cursos gratuitos do WebDevBr! - Inscreva-se!


Este artigo foi publicado a 4 anos, 1 mês, 1 dia atrás.

Como já devo ter comentado antes, a função principal das normas PSR é formar um padrão universal de desenvolvimento, de forma que códigos de diferentes autores possam coexistir entre si sem causar nenhum transtorno, a PSR-2 estende o que vimos na PSR-1, definindo padrões de escrita que visam não somente a interoperabilidade (a capacidade de comunicação já citada), mas também um arquivo mais organizado e simples de se ler e entender.

Esta regra engloba muitas regras e pode ser complicada de se colocar em prática com perfeição, mas para isso existe um validador, vou falar dele no fim do artigo.

Então vamos as regras:

Gostou deste artigo?

Receba atualizações semanais com novos artigos do WebDevBr e outras dicas!

Visão geral

Aqui o repositório no github oficial.

E aqui em português.

O código DEVE seguir a PSR-1.

Como não podia deixar de ser, a primeira regra da PSR-2 é que ela deve seguir a PSR-1, que por sua vez, segue a PSR-0, ou seja, para aplicar esta regra corretamente você deve antes aplicar as anteriores.

O código DEVE usar 4 espaços para indentação ao invés de tabs.

Sabe quando você vai criar uma classe, ou uma função ou um if() e da um tab dentro para poder indicar que aquele bloco de código está dentro de algo, então você não deve mais fazer isso, em vez do tab, o correto é usar 4 espaços, veja:

class Erik
{
    public function alves()
    {
        if($figueiredo){
            return 'Sou eu sim!';
        }
    }
}

Exemplo mais mal caráter, mas enfim a indentação são estes espaços brancos antes de começarmos a escrever, simples né a maioria das IDEs que testei faz isso automaticamente, mas fique atento quando estiver desenvolvendo e pare de usar o tab.

Se ainda restou alguma dúvida sobre indentação:

Em tipografia, indentação é o recuo de um texto em relação a sua margem.

NÃO DEVE haver um limite rigoroso (hard limit) no comprimento das linhas; o limite suave (soft limit) DEVE ser de 120 caracteres; linhas DEVERIAM ser de 80 caracteres ou menos.

Embora eu não saia contando quantos caracteres existam em uma linha, levo por base que sempre que puder quebrá-la em uma segunda, terceira ou mais linhas eu faço, ifs por exemplo não precisam ficar escritos direto, ainda mais quando existe mais de uma condição no mesmo, as vezes separa-lo em várias linhas ajuda a reduzir a dificuldade de se entender o que aquilo faz.

Eu poderia pegar este bloco de código...

if((($erik=='Erik') and ($figueiredo=='Figueiredo')) or (($freelancer==true) and ($profissao!='médico'))){
}

...e fazer isso:

if(
    (
        ($erik=='Erik')
        and
        ($figueiredo=='Figueiredo')
    ) or (
        ($freelancer==true)
        and
        ($profissao!='médico'))
    )
{
/* Mais códigos */
}

É claro que tudo pelo bem da legibilidade, note que a regra estabelece 3 pontos:

  • Não deve existir um limite no hard limit, o hard limit estabelece um tamanho máximo de quantidade de caracteres que pode existir em uma linha, ou seja, isso não deve acontecer.
  • O soft limit deve ser de 120 caracteres, ou seja, após 120 caracteres sua IDE tem que te avisar que você está ou passou deste limite, ou você tem que manter um controle que te indique que isto está acontecendo.
  • Porém o recomendado é que uma linha tenha um máximo de 80 caracteres, no máximo, a RFC 2119 deixa claro que o recomendado aqui significa que "Não podem existir razões válidas, em circunstâncias particulares para ignorar isto", mas claro, se você quiser.

Obs.: A linha do meu if do exemplo tem 107 caracteres.

Note bem: Usando apenas espaços e não misturando espaços com tabs ajuda a evitar problemas com diffs, patches, history e annotations. O uso de espaços também torna mais fácil inserir sub-indentação refinada para alinhamento na entrelinha.

DEVE haver uma linha em branco após a declaração do namespace e DEVE haver uma linha em branco após o bloco de declarações use.

Bem fácil né, após o namespace, pule uma linha e depois de declarar os use pule outra linha:

<?php
namespace VendorPackage;

use FooInterface;
use BarClass as Bar;
use OtherVendorOtherPackageBazClass;

class Foo extends Bar implements FooInterface
{
...

Outra coisa apresentada no exemplo e que deve acontecer é que os use devem vir sempre após o namespace e cada use tem que estar em uma linha com um use no começo, nada de abreviar.

A abertura de chaves para classes DEVE estar na próxima linha e o fechamento na próxima linha DEVE estar na próxima linha após o corpo.

Bem simples essa regra, as chaves ({}) devem ser colocadas assim:

class Foo extends Bar implements FooInterface
{
...
}

E não assim:

class Foo extends Bar implements FooInterface{
...}

A abertura de chaves para métodos DEVE estar na próxima linha e o fechamento na próxima linha DEVE estar na próxima linha após o corpo.

O mesmo da regra anterior, mas desta vez com métodos (function):

public function foo()
{
    ...
}

O mesmo se aplica a interfaces e traits.

Vale citar a regra:

Listas de implements PODEM ser dividas em múltiplas linhas, onde cada linha subsequente é indentada uma vez. Quando fizer isto, o primeiro item na lista DEVE estar na próxima linha e DEVE haver uma interface por linha.

A visibilidade DEVE ser declarada em todas as propriedades e métodos; as palavras-chave abstract e final DEVEM ser declaradas antes da visibilidade; a palavra-chave static DEVE ser declarada após a visibilidade.

Hum, aqui entra uma coisa que até muito recentemente eu não fazia, declaras a visibilidade dos métodos (function), por padrão, quando você cria uma função do PHP sem declarar public, private ou protected ela se torna uma função pública, porém a partir do momento que que você passar a declarar o public antes do método vai se ver descobrindo que determinada função não deve ser vista por outras classes e vai organizar e proteger melhor sua aplicação.

Se não conhece a visibilidade do PHP OOP, então aqui vai:

  • Public: Pode ser usada por qualquer classe em qualquer lugar
  • Protected: Pode ser usada por qualquer classe que estenda a atual (extends) e vise-versa, mas se você chamar a classe com $var=new Classe() ela não vai estar disponível
  • Private: Só pode ser usada pela classe atual e em nenhum outro lugar.

Já as palavras-chave abstract e final devem ser declaradas quando necessário, mas antes da visibilidade.

A palavras-chave final serve para dizer que esta função não pode ser sobrescrita mais, ou seja, se você criar uma classe e estender esta o método figueiredo() não vai poder ser usado, vai gerar um erro. Já a abstract força a classe filha a criar os métodos. Se quiser saber mais do assunto consulte a documentação do PHP.

Já a palavra-chave static deve ser enviada após a visibilidade e faz com que o método possa ser chamado mesmo que a classe não esteja instanciada.

Só pra reforçar: as propriedades que a regra se refere são as variáveis declaradas no começo da classe, ou seja, o mesmo vale vara elas e nunca use a palavra-chave var para definir as propriedades.

class Erik
{

    public static $var='erik';

    protected function alves()
    {
        return true;
    }
    final public function figueiredo()
    {
        return false;
    }

    public static function nome($nome)
    {
        return $nome;
    }
}

echo Erik::nome('Erik Figueiredo') . "n";
echo Erik::$var . "n";

Ainda vale citar duas regras:

NÃO DEVE haver mais de uma propriedade declarada por instrução.

Os nomes das propriedades e métodos NÃO DEVERIAM ser prefixados com um único underline para indicar a visibilidade protegida ou privada.

As palavras-chave de estruturas de controle DEVEM ter um espaço depois delas; chamadas de métodos e funções NÃO DEVEM.

Simples, palavras-chave de controle (if, while, for, foreach, switch) dever ter um espaço após elas, mas isso antes das chaves ({).

Certo:

if (true) {
    ...
}

Errado:

if(true){
    ...
}

Mas isso não vale para métodos, eles não devem ter espaços após eles.

A abertura de chaves para estruturas de controle DEVE estar na mesma linha e o fechamento DEVE estar na próxima linha após o corpo.

Lembra que quando eu falei das chaves ({}) de funções devem começar na linha seguinte, então, pois é, ifs e afins devem ser na mesma linha, então complementando a regra anterior o certo é:

palavra-chave()espaço{  
    4espaçosCorpoDoCódigo  
}

Não vou postar exemplos, tem um monte aqui neste artigo, acima.

A abertura de parênteses para estruturas de controle NÃO DEVE ter um espaço depois dela e o fechamento de parênteses para estruturas de controle NÃO DEVE ter um espaco antes.

Também é simples, quando declaras seus ifs e afins dentro do parenteses não pode ter espaço logo após ele abrir e nem antes dele fechar, ou seja (semEspaçosAqui sua função nemAqui).

Exemplo

Este é o exemplo da própria documentação da PSR-2:

<?php
namespace VendorPackage;

use FooInterface;
use BarClass as Bar;
use OtherVendorOtherPackageBazClass;

class Foo extends Bar implements FooInterface
{
    public function sampleFunction($a, $b = null)
    {
        if ($a === $b) {
            bar();
        } elseif ($a > $b) {
            $foo->bar($arg1);
        } else {
            BazClass::bar($arg2, $arg3);
        }
    }

    final public static function bar()
    {
        // corpo do método
    }
}

Geral

Arquivos

Todos os arquivos PHP DEVEM usar o fim da linha Unix LF (linefeed).

Sabe aquele n qye usamos como quebra de linha no PHP, então, é isso, nada de usar o padrão para Windows(rn), é padrão Linux e pronto.

Todos os arquivos PHP DEVEM terminar com uma única linha em branco.

Fácil, a última linha do arquivo PHP deve estar em branco.

A tag de fechamento ?> DEVE ser omitida em arquivos que contêm somente PHP.

Isso gera um incomodo desnecessário muitas vezes, sabe quando você tenta setar um header e o PHP diz que não pode fazer isso porque já foi enviado uma saída HTML, a culpa pode ser disso.

Linhas

NÃO DEVE haver espaço em branco no final de linhas não-em-branco.

As linhas em branco PODEM ser adicionadas para aumentar a legibilidade e para indicar blocos de código relacionados.

NÃO DEVE haver mais de um comando (statement) por linha.

Palavras-chave e True/False/Null

Palavras-chave do PHP DEVEM ser em letra minúscula (lower case).

Pra quem ficou na dúvida sobre as palavras chave

As constantes do PHP true, false e null DEVEM ser em letra minúscula (lower case).

Argumentos de Métodos

Na lista de argumentos, NÃO DEVE haver um espaço antes de cada vírgula e DEVE haver um espaço após cada vírgula.

Os argumentos de métodos com valor padrão DEVEM vir no final da lista de argumentos.

class ClassName
{
    public function foo($arg1, &#038;$arg2, $arg3 = [])
    {
        // corpo do método
    }
}

As listas de argumentos PODEM ser dividas em múltiplas linhas, onde cada linha subsequente é indentada uma vez. Quando fizer isto, o primeiro item na lista DEVE estar na próxima linha e DEVE haver um argumento por linha.

Quando a lista de argumento for dividida em múltiplas linhas, o parêntese de fechamento e a chave de abertura DEVEM ser colocados na mesma linha com um espaço entre eles.

<?php
namespace VendorPackage;

class ClassName
{
    public function umNomeDeMetodoMuitoLongo(
        ClassTypeHint $arg1,
        &#038;$arg2,
        array $arg3 = []
    ) {
        // corpo do método
    }
}

Estruturas de Controle

Ainda existem as regras para estruturas de controle, ou seja, para if, else, ifelse, switch, case, while, do while, for, foreach, try e catch.

As regras aqui são bem claras e fáceis de entender:

  • DEVE haver um espaço depois da palavra-chave da estrutura de controle
  • NÃO DEVE haver espaço depois do parêntese de abertura
  • NÃO DEVE haver espaço depois do parêntese de fechamento
  • DEVE haver um espaço entre o parêntese de fechamento e a chave de abertura
  • A estrutura do corpo DEVE ser indentada uma vez
  • A chave de fechamento DEVE vir na próxima linha após o corpo

Só os conjuntos if, else e ifelse e switch e case possuem regras próprias, os outros se baseiam no escrito acima.

  • Else e elseif são na mesma linha da chave de fechamento do corpo anterior.
  • A palavra-chave elseif DEVERIA ser usada ao invés de else if, de modo que todas as estruturas de controle pareçam uma única palavra.
  • A declaração case DEVE ser indentada uma vez do switch
  • A palavra-chave break (ou outra palavra-chave de finalização) DEVE ser indentada no mesmo nível do corpo de case.
  • DEVE haver um comentário como // no break quando é intencional cair ("fall-through") num case com corpo não-vazio.

E alguns exemplos:

<?php
if ($expr1) {
    // corpo if
} elseif ($expr2) {
    // corpo elseif
} else {
    // corpo else;
}

switch ($expr) {
    case 0:
        echo 'Primeiro caso, com uma quebra';
        break;
    case 1:
        echo 'Segundo caso, que "cai" para o(s) seguinte(s)';
        // no break
    case 2:
    case 3:
    case 4:
        echo 'Terceiro caso, return é usado ao invés de break';
        return;
    default:
        echo 'Caso padrão';
        break;
}

while ($expr) {
    // corpo de estrutura
}

do {
    // corpo de estrutura;
} while ($expr);

for ($i = 0; $i < 10; $i++) {
    // corpo de for
}

foreach ($iterable as $key => $value) {
    // corpo de foreach
}

try {
    // corpo de try
} catch (FirstExceptionType $e) {
    // corpo de catch
} catch (OtherExceptionType $e) {
    // corpo de catch
}

Closures

Closures são as funções não nomeadas, sabe aquelas que você usa nos callbacks ou que armazena em variáveis? Não, então você verá alguns ótimos exemplos na documentação do PHP.

As regras para closures são:

  • As closures DEVEM ser declaradas com um espaço depois da palavra-chave function e um espaço antes e depois da palavra-chave use.
  • A chave de abertura DEVE vir na mesma linha e a chave de fechamento DEVE vir na próxima linha após o corpo.
  • NÃO DEVE haver um espaço após o parêntese de abertura de uma lista de argumentos ou lista de variáveis e NÃO DEVE haver um espaço antes do parêntese de fechamento da lista de argumentos ou lista de variáveis.
  • Na lista de argumentos e na lista de variáveis, NÃO DEVE haver um espaço antes de cada vírgula e DEVE haver um espaço depois de cada vírgula.
  • Os argumentos de closure com valores padrão DEVEM vir depois da lista de argumentos.
  • As listas de argumento e listas de variáveis PODEM ser divididas em múltiplas linhas, onde cada linha subsequente é indentada uma vez. Quando fizer isso, o primeiro item na lista DEVE estar na próxima linha e DEVE haver um argumento ou variável por linha.
  • Quando a lista de argumento ou lista de variáveis forem dividida em múltiplas linhas, o parêntese de fechamento e a chave de abertura DEVEM ser colocados na mesma linha com um espaço entre eles.

    $closureWithArgs = function ($arg1, $arg2) { // corpo };

    $closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) { // corpo };

    $longArgs_noVars = function ( $longArgument, $longerArgument, $muchLongerArgument ) { // corpo };

    $noArgs_longVars = function () use ( $longVar1, $longerVar2, $muchLongerVar3 ) { // corpo };

    $longArgs_longVars = function ( $longArgument, $longerArgument, $muchLongerArgument ) use ( $longVar1, $longerVar2, $muchLongerVar3 ) { // corpo };

    $longArgs_shortVars = function ( $longArgument, $longerArgument, $muchLongerArgument ) use ($var1) { // corpo };

    $shortArgs_longVars = function ($arg) use ( $longVar1, $longerVar2, $muchLongerVar3 ) { // corpo };

    $foo->bar( $arg1, function ($arg2) use ($var1) { // corpo }, $arg3 );

Note que as regras de formatação também se aplicam quando a closure é usada diretamente em uma chamada de função ou método como um argumento.

Usando o validador

As regras são verdadeiramente muito simples, mas pode ser trabalhoso de se acostumar com tudo de uma vez, pensando nisso o pessoal da PHPFIG desenvolveu um validador pra ajudar nas tarefas, diversas IDEs podem ser integradas.

O validador das PSRs usa o CodeSniffer do PHP e para usar vamos precisar configurar o php no patch do sistema para usarmos no console.

Lembrando que ele vai validar apenas as PSRs 0,1 e 2 ok.

Primeiramente acesse o console (CMD no Windows).

Acesse esta página e pegue o comando para a versão mais recente (vamos instalar via PEAR).

Neste momento é:

pear install PHP_CodeSniffer-1.5.0RC4

Rode o comando

Se parecer escrito Install ok: channel mais alguma coisa, foi tudo certo.

Agora para usar:

phpcs /caminho/para/o/meuphp.php

Ele vai retornar os erros encontrados em cada linha no arquivo em questão para você corrigir.

Se você, assim como eu, usa o Windows pra desenvolver (já estou resolvendo isso, baixei o Ubuntu Server, mas ainda não criei vergonha na cara pra instalar) ele sempre vai retornar o erro de quebra de linha, como citado acima, o correto é '/n', mas o Windows usa '/r/n', em algumas IDEs você consegue contornar isso.

Exemplo de como usar o line break correto no Windows usando o Dreamweaver.

Abra o arquivo e de um control+f e procure por [rn] marcando para usar expressões regulares em replace (substituir) coloque n. Substitua tudo.

Depois vá em Edit >Preferences > Code Format e troque o Line break type para LF (Unix) e salve.

Prontinho, problema resolvido... no Dreamweaver CS6.

O Notepad++, também é uma alternativa que na minha opinião resolveu o problema do tab e dos 4 espaços muito melhor.

Conclusão

Embora o uso da PSR-2 sejam mais "estéticos do que funcionais" (note as aspas) o uso desta regra acaba que se tornando algo não tão obrigatório, porém pense no seu crescimento profissional, se você se adaptar a estas regras estará apto a trabalhar com outros programadores também adeptos sem que tenha inconvenientes e discussões, facilitando o entendimento dos códigos para todas as partes envolvidas.

Já tenho os arquivos de um framework simples para ilustrar tudo isso de forma prática, penso em fazer uma nova série sobre o assunto, tratando deste framework e sempre validando os arquivos com o CodeSniffer.


Cursos relacionados


* Parcelamento apenas cartão de crédito! Pode haver uma pequena variação no parcelamento em relação a simulações apresentadas!