Estilo de Codificação

Demarcação de código PHP

Código PHP deve sempre ser delimitado pelas tags na forma completa, padrão do PHP:

<?php

?>

Tags reduzidas nunca não permitidas. Para arquivos que contenham somente código PHP, a tag de fechamento deve sempre ser omitida (veja a seção Geral).

Strings

Strings literais

Quando uma string é literal (não contém substituição de variáveis), o apóstrofo ou "aspa simples" deve sempre ser utilizado para demarcar a string:

$a = 'Example String';

Strings literais contendo apóstrofos

Quando uma string literal em si contém apóstrofos, é permitido demarcar a string com aspas ou "aspas duplas". Isto é especialmente útil para sentenças SQL:

$sql = "SELECT `id`, `name` from `people` "
     . "WHERE `name`='Fred' OR `name`='Susan'";

Esta sintaxe é preferível a escapar os apóstrofos uma vez que é muito mais legível.

Substituição de variáveis

A substituição de variáveis é permitida utilizando qualquer uma destas formas:

$greeting = "Hello $name, welcome back!";

$greeting = "Hello {$name}, welcome back!";

Por consistência, esta forma não é permitida:

$greeting = "Hello ${name}, welcome back!";

Concatenação de strings

Strings devem ser concatenadas utilizando o operador ".". Um espaço deve sempre ser adicionado antes e depois do operador "." para melhorar a legibilidade:

$company = 'Zend' . ' ' . 'Technologies';

Ao concatenar strings com o operador "." encoraja-se quebrar a expressão em múltiplas linhas para facilitar a leitura. Nestes casos, cada linha sucessiva deve ser indentada com espaços em branco de forma que o operador "." fique alinhado com o operador "=":

$sql = "SELECT `id`, `name` FROM `people` "
     . "WHERE `name` = 'Susan' "
     . "ORDER BY `name` ASC ";

Arrays

Arrays numericamente indexados

Números negativos não são permitidos como índices.

Um array indexado deve iniciar com um número não-negativo. Entretanto, índices iniciados em números diferentes de 0 são desencorajados.

Ao declarar arrays indexados com a função Array, um espaço deve ser adicionado após cada vírgula delimitadora para aumentar a legibilidade:

$sampleArray = array(1, 2, 3, 'Zend', 'Studio');

É permitido declarar arrays indexados em várias linhas utilizando o construtor "array". Neste caso, cada linha sucessiva deve ser indentada com espaços de forma que o começo de cada linha fique alinhado:

$sampleArray = array(1, 2, 3, 'Zend', 'Studio',
                     $a, $b, $c,
                     56.44, $d, 500);

Alternativamente, o item inicial do array pode começar na linha seguinte. Neste caso, ele deve ser indentado em um nível a mais que a linha que contém a declaração do array e todas as linhas sucessivas devem ter a mesma indentação. O parêntese de fechamento deve estar em uma linha a parte no mesmo nível de indentação da linha que contém a declaração do array:

$sampleArray = array(
    1, 2, 3, 'Zend', 'Studio',
    $a, $b, $c,
    56.44, $d, 500,
);

Ao usar esta última declaração, encorajamos utilizar uma vírgula após o último item do array. Isto minimiza o impacto de adicionar novos itens em linhas sucessivas e ajuda a garantir que nenhum erro ocorra devido à ausência de uma vírgula.

Arrays associativos

Ao declarar arrays associativos com o construtor Array, encoraja-se quebrar a expressão em várias linhas. Neste caso, cada linha sucessiva deve ser indentada com espaços em branco de forma que as chaves e os valores fiquem alinhados:

$sampleArray = array('firstKey'  => 'firstValue',
                     'secondKey' => 'secondValue');

Alternativamente, o item inicial do array pode começar na linha seguinte. Neste caso, ele deve ser indentado a um nível a mais que a linha contendo a declaração do array e todas as linhas sucessivas devem ter a mesma indentação. O parêntese de fechamento deve estar em uma linha própria, no mesmo nível de indentação da linha que contém a declaração do array. Para legibilidade, os vários operadores de atribuição "=>" devem ser espaçados de forma a ficarem alinhados.

$sampleArray = array(
    'firstKey'  => 'firstValue',
    'secondKey' => 'secondValue',
);

Ao utilizar esta última declaração, encorajamos utilizar uma vírgula após o último item do array; isto minimiza o impacto de adicionar novos itens em linhas sucessivas e ajuda a garantir que nenhum erro ocorra devido à ausência de uma vírgula.

Classes

Declaração de classe

Classes devem ser nomeadas de acordo com a convenção de nomenclatura do Zend Framework.

A chave deve ser sempre escrita na linha abaixo do nome da classe.

Toda classe deve ter um bloco de documentação em conformidade ao padrão do PHPDocumentor.

Todo código em uma classe deve ser indentado com quatro espaços.

Apenas uma única classe é permitida em cada arquivo PHP.

A inserção de código adicional em arquivos de classe é permitida, mas desencorajada. Em tais arquivos, duas linhas em branco devem separar a classe de qualquer código PHP no arquivo.

A seguir, um exemplo de declaração de classe aceitável:

/**
 * Bloco de documentação aqui.
 */
class SampleClass
{
    // todo conteúdo de classe
    // deve ser indentado quatro espaços
}

Classes que estendem outras classes ou que implementam interfaces devem declarar suas dependências na mesma linha, quando possível.

class SampleClass extends FooAbstract implements BarInterface
{
}

Se estas operações fizerem com que o comprimento da linha exceda o comprimento máximo, quebre a linha antes das palavras-chave "extends" e/ou "implements", e indente tais linhas em mais um nível.

class SampleClass
    extends FooAbstract
    implements BarInterface
{
}

Se a classe implementa múltiplas interfaces e a declaração excede o comprimento máximo da linha, quebre após cada interface separada por vírgula e indente os nomes das interfaces de forma a ficarem alinhados.

class SampleClass
    implements BarInterface,
               BazInterface
{
}

Variáveis membras de classes

Variáveis-membras devem ser nomeadas de acordo com as convenções de nomenclatura de variáveis do Zend Framework.

Quaisquer variáveis declaradas em uma classe devem ser listadas no topo da classe, acima da declaração de quaisquer métodos.

O construtor var não é permitido. Variáveis-membras devem sempre declarar sua visibilidade usando um dos modificadores private, protected ou public. Dar acesso direto a variáveis-membras declarando-as como públicas é permitido mas desencorajado. Em vez disso, utilize métodos acessores (set e get).

Funções e métodos

Declaração de funções e métodos

Funções devem ser nomeadas de acordo com as convenções de nomenclatura do Zend Framework.

Métodos dentro de classes devem sempre declarar sua visibilidade usando um dos modificadores private, protected ou public.

Assim como ocorre com classes, a chave deve sempre ser escrita na linha abaixo do nome da função. Espaços entre o nome da função e o parêntese de abertura para os argumentos não são permitidos.

Funções em escopo global são fortemente desencorajadas.

A seguir, um exemplo de declaração aceitável de função em uma classe:

/**
 * Bloco de documentação aqui
 */
class Foo
{
    /**
     * Bloco de documentação aqui
     */
    public function bar()
    {
        // todo conteúdo de função
        // deve ser identado quatro espaços
    }
}

Quando a lista de argumentos exceder o comprimento máximo de linha você pode introduzir quebras de linha. Argumentos adicionais à função/método devem ser identados um nível a mais que o da declaração da função/método. Uma quebra de linha deve ser colocada antes do parêntese de fechamento de argumentos, que deve então ser colocado na mesma linha da chave de abertura da função/método com uma espaço separando os dois, e no mesmo nível de identação da declaração da função/método. A seguir, um exemplo de tal situação:

/**
 * Bloco de documentação aqui
 */
class Foo
{
    /**
     * Bloco de documentação aqui
     */
    public function bar($arg1, $arg2, $arg3,
        $arg4, $arg5, $arg6
    ) {
        // todo conteúdo de função
        // deve ser identado quatro espaços
    }
}

Nota

O único mecanismo de passagem de parâmetro permitido em uma declaração de método é a passagem por referência.

/**
 * Bloco de documentação aqui
 */
class Foo
{
    /**
     * Bloco de documentação aqui
     */
    public function bar(&$baz)
    {}
}

Passagem por referência em tempo de chamada é estritamente proibido.

O valor de retorno não deve ser cercado por parênteses. Isto pode embaraçar a legibilidade, além de quebrar o código caso um método seja modificado posteriormente para retornar por referência.

/**
 * Bloco de documentação aqui
 */
class Foo
{
    /**
     * ERRADO
     */
    public function bar()
    {
        return($this->bar);
    }

    /**
     * CERTO
     */
    public function bar()
    {
        return $this->bar;
    }
}

Uso de funções e métodos

Argumentos de funções devem ser separados por um único espaço após a vírgula delimitadora. A seguir, um exemplo de chamada aceitável de função que utiliza três argumentos:

threeArguments(1, 2, 3);

Passagem por referência em tempo de chamada é estritamente proibido. Veja na seção de declaração de funções a maneira apropriada de passar argumentos de função por referência.

Ao passar arrays como argumentos para uma função, a chamada da função pode incluir a indicação "array" e pode ser quebrada em múltiplas linhas para aumentar a legibilidade. Em tais casos, as instruções para a escrita de arrays ainda se aplicam:

threeArguments(array(1, 2, 3), 2, 3);

threeArguments(array(1, 2, 3, 'Zend', 'Studio',
                     $a, $b, $c,
                     56.44, $d, 500), 2, 3);

threeArguments(array(
    1, 2, 3, 'Zend', 'Studio',
    $a, $b, $c,
    56.44, $d, 500
), 2, 3);

Expressões de controle

If/Else/Elseif

Expressões de controle baseadas nos construtores if e elseif devem ter um único espaço antes do parêntese de abertura do condicional e um único espaço depois do parêntese de fechamento.

Dentro das expressões condicionais entre os parênteses, os operadores devem ser separados por espaços para maior legibilidade. Parênteses aninhados são encorajados a fim de melhorar o agrupamento lógico de expressões condicionais maiores.

A chave de abertura deve ser escrita na mesma linha da expressão condicional, enquanto a chave de fechamento deve sempre ser escrita na sua própria linha. Qualquer conteúdo dentro das chaves deve ser indentado utilizando quatro espaços.

if ($a != 2) {
    $a = 2;
}

Se a expressão condicional fizer com que a linha exceda o comprimento máximo e possuir várias cláusulas você pode quebrar a condicional em várias linhas. Em tais casos, quebre a linha antes de um operador lógico e indente a linha de forma a ficar alinhada abaixo do primeiro caractere da cláusula condicional. O parêntese de fechamento no condicional será então colocado em uma linha junto à chave de abertura com um espaço separando os dois, em um nível de indentação equivalente ao da expressão de controle de abertura.

if (($a == $b)
    && ($b == $c)
    || (Foo::CONST == $d)
) {
    $a = $d;
}

A intenção deste último formato de declaração é prevenir problemas ao adicionar ou remover cláusulas da condicional durante revisões posteriores.

Para expressões "if" que incluem "elseif" ou "else", as convenções de formatação são similares às do construtor "if". Os exemplos a seguir demonstram a formatação apropriada para expressões "if" com construtores "else" e/ou "elseif":

if ($a != 2) {
    $a = 2;
} else {
    $a = 7;
}

if ($a != 2) {
    $a = 2;
} elseif ($a == 3) {
    $a = 4;
} else {
    $a = 7;
}

if (($a == $b)
    && ($b == $c)
    || (Foo::CONST == $d)
) {
    $a = $d;
} elseif (($a != $b)
          || ($b != $c)
) {
    $a = $c;
} else {
    $a = $b;
}

O PHP permite que expressões sejam escritas sem chaves em algumas circunstâncias. Este padrão de codificação, no entando, não faz diferenciação alguma -- todas expressões "if", "elseif" ou "else" devem utilizar chaves.

Switch

Expressões de controle escritas com a expressão "switch" devem ter um único espaço antes do parêntese de abertura da expressão condicional e após o parêntese de fechamento.

Todo o conteúdo dentro da expressão "switch" deve ser indentado utilizando quatro espaços e o conteúdo abaixo de cada expressão "case" deve ser indentado utilizando quatro espaços adicionais.

switch ($numPeople) {
    case 1:
        break;

    case 2:
        break;

    default:
        break;
}

O construtor default nunca deve ser omitido de uma expressão switch.

Nota

Em alguns casos é útil escrever uma expressão case que recai sobre a próxima omitindo um break ou return. Para diferenciar tais casos de bugs, qualquer expressão case onde o break ou o return sejam omitidos devem conter um comentário indicando que a quebra foi intencionalmente omitida.

Documentação em linha de código

Formato de documentação

Todos blocos de documentação ("docblocks") devem ser compatíveis com o formato phpDocumentor. Descrever o formato phpDocumentor está além do escopo deste documento. Para mais informações, visite: http://phpdoc.org/

Todo arquivo de classe deve conter um docblock em nível de arquivo no topo de cada arquivo e um docblock em nível de classe imediatamente acima da classe. Exemplos de tais docblocks podem ser vistos abaixo.

Arquivos

Todo arquivo que contém código PHP deve ter um docblock no topo do arquivo contendo no mínimo estas tags do phpDocumentor:

/**
 * Descrição resumida do arquivo
 *
 * Descrição longa do arquivo (se houver)...
 *
 * LICENÇA: Informação sobre licença
 *
 * @category   Zend
 * @package    Zend_Magic
 * @subpackage Wand
 * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license   BSD License
 * @version    $Id:$
 * @link       http://framework.zend.com/package/PackageName
 * @since      File available since Release 1.5.0
*/

A anotação @category deve ter o valor "Zend".

A anotação @package deve ser utilizada e deve ser equivalente ao nome do componente da classe contida no arquivo. Tipicamente, o nome do componente possuirá apenas dois segmentos, o prefixo "Zend" e o nome do componente.

A anotação @subpackage é opcional. Caso informada, deve ser o nome do subcomponente menos o prefixo da classe. No exemplo acima, assume-se que a classe no arquivo ou é "Zend_Magic_Wand" ou utiliza tal nome de classe como parte de seu prefixo.

Classes

Toda classe deve ter um docblock que contenha no mínimo estas tags do phpDocumentor:

/**
 * Descrição resumida da classe
 *
 * Descrição longa da classe (se houver)...
 *
 * @category   Zend
 * @package    Zend_Magic
 * @subpackage Wand
 * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license   BSD License
 * @version    Release: @package_version@
 * @link       http://framework.zend.com/package/PackageName
 * @since      Class available since Release 1.5.0
 * @deprecated Class deprecated in Release 2.0.0
 */

A anotação @category deve ter o valor "Zend".

A anotação @package deve ser informada e deve ser equivalente ao componente a que a classe pertence; tipicamente, terá apenas dois segmentos: o prefixo "Zend" e o nome do componente.

A anotação @subpackage é opcional. Caso informada, deve ser o nome do subcomponente menos o prefixo da classe. No exemplo acima, assume-se que a classe descrita ou é "Zend_Magic_Wand" ou utiliza este nome como parte do seu prefixo.

Funções

Toda função, incluindo métodos de objetos, deve possuir um docblock que contenha no mínimo:

  • Uma descrição da função

  • Todos os argumentos

  • Todos os possíveis valores de retorno

Não é necessário utilizar a tag "@access" já que o nível de acesso é conhecido através do modificador "public", "private" ou "protected" utilizado na declaração.

Se uma função ou método pode disparar uma exceção, utilize @throws para todas as classes de exceção:

@throws exceptionclass [description]