Padrão de Codificação do Zend Framework para PHP Visão geral Escopo Este documento fornece instruções para formatação e documentação de código a indivíduos e times que contribuem com o Zend Framework. Muitos desenvolvedores que utilizam o Zend Framework acham que estes padrões são igualmente importantes para que seu estilo de codificação permaneça consistente com todo o código do Framework. Vale também notar que é necessário esforço significativo para especificar padrões de codificação por completo. Por vezes, desenvolvedores consideram o estabelecimento de um padrão mais importante do que o padrão sugere de verdade ao nível mais detalhado de design. As instruções nos padrões de codificação do Zend Framework absorvem práticas que funcionaram bem no projeto do Framework. Você pode alterar tais padrões ou usá-los "as is" de acordo com os termos de nossa licença. Os tópicos abordados nos padrões de codificação do Zend Framework incluem: Formatação de arquivos PHP Convenções de nomenclatura Estilo de codificação Documentação em linha de código Objetivos Padrões de codificação são importantes em qualquer projeto de desenvolvimento, mas são particularmente importantes quando muitos desenvolvedores estão trabalhando no mesmo projeto. Eles ajudam a garantir que o código possua alta qualidade, poucos bugs e possam ser facilmente mantidos. Formatação de Arquivos PHP Geral Para arquivos que contenham somente código PHP, a tag de fechamento ("?>") nunca é permitida. Ela não é exigida pelo PHP e omiti-la previne a injeção acidental de espaços em branco desnecessários na resposta. Importante: A inclusão de dados binários arbitrários, como permitido pela função __HALT_COMPILER(), é proibida a partir de arquivos PHP no projeto Zend Framework ou de arquivos derivados deles. O uso deste recurso é permitido somente para alguns scripts de instalação. Indentação A indentação deve consistir de 4 espaços. Tabulações não são permitidas. Comprimento máximo de linha O comprimento desejável das linhas é 80 caracteres. Isto significa que desenvolvedores do Zend Framework devem se esforçar para manter cada linha de seus códigos com menos que 80 caracteres onde possível e prático. Entretanto, linhas maiores são aceitáveis em algumas circunstâncias. O comprimento máximo de qualquer linha de código PHP é 120 caracteres. Quebra de linha Quebras de linha seguem a convenção de arquivos de texto Unix. As linhas devem terminar com um único caractere de quebra -- linefeed (LF). Caracteres de quebra são representados como ordinal 10 ou hexadecimal 0x0A. Nota: Não use retornos -- carriage returns (CR) -- como é a convenção em arquivos dos sistemas Apple (0x0D) ou a combinação de retorno e quebra (CRLF), como é o padrão dos sistemas Windows (0x0D, 0x0A). Convenções de Nomenclatura Classes O Zend Framework utiliza um padrão de nomes de classes de forma que os nomes das classes mapeiam diretamente os diretórios onde estão armazenadas. O diretório raiz da biblioteca padrão do Zend Framework é o diretório "Zend/" e o diretório raiz da biblioteca de extras é "ZendX/". Todas as classes do Zend Framework são armazenadas hierarquicamente sob tais diretórios. Nomes de classes devem conter somente caracteres alfanuméricos. Números são permitidos em nomes de classes mas são desencorajados na maioria dos casos. Underscores são permitidos somente no lugar de separador de diretórios. O arquivo "Zend/Db/Table.php", por exemplo, deve mapear a classe de nome "Zend_Db_Table". Se um nome de classe é composto de mais de uma palavra, a primeira letra de cada nova palavra deve ser maiúscula. Letras maiúsculas em sequência não são permitidas. A classe "Zend_PDF", por exemplo, não é permitida, enquanto "Zend_Pdf" é. Estas convenções definem um mecanismo de pseudonamespace para o Framework. O Zend Framework irá adotar o recurso de namespace do PHP assim que ele se tornar disponível e prático para nossos desenvolvedores os utilizarem em suas aplicações. Exemplos desta convenção de nomenclatura podem ser vistos em nomes de classes nas bibliotecas padrão e de extras. Importante: Códigos que devem ser disponibilizados junto às bibliotecas do Zend Framework mas não são parte das bibliotecas padrão ou de extras (por exemplo, código de aplicação ou bibliotecas que não são distribuídas pela Zend) nunca devem iniciar com "Zend_" ou "ZendX_". Classes abstratas Em geral, classes abstratas seguem as mesmas convenções de classes, com uma regra adicional: nomes de classes abstratas devem terminar com o termo "Abstract", que não pode ser precedido por um underscore. Por exemplo, Zend_Controller_Plugin_Abstract é considerado um nome inválido, mas Zend_Controller_PluginAbstract ou Zend_Controller_Plugin_PluginAbstract seriam nomes válidos. Esta convenção de codificação é nova na versão 1.9.0 do Zend Framework. Classes de datas anteriores a esta versão podem não seguir esta regra mas serão renomeadas no futuro a fim de obedecê-la. A razão de tal mudança é o uso de namespace. Como pretendemos que o Zend Framework 2.0 utilize PHP 5.3, utilizaremos namespaces. A maneira mais fácil de automatizar a conversão para namespaces é simplemente converter underscores para o separador de namespace -- mas sob as antigas convenções de nomenclatura isto deixa o nome da classe como somente "Abstract" ou "Interface" -- as quais são palavras-chave reservadas em PHP. Se prefixarmos o nome do (sub)componente ao nome da classe, podemos evitar tais problemas. Para ilustrar a situação, considere converter a classe Zend_Controller_Request_Abstract para utilizar namespaces: Claramente isto não irá funcionar. Sob as novas convenções de nomenclatura, entretanto, isso se tornaria: Ainda retemos a semântica e a separação de namespace enquanto omitimos os problemas com palavras-chave; ao mesmo tempo, a classe abstrata é melhor descrita. Interfaces Em geral, interfaces seguem as mesmas convenções de classes, com uma regra adicional: nomes de interface podem opcionalmente terminar com o termo "Interface", que não pode ser precedido por um underscore. Por exemplo, Zend_Controller_Plugin_Interface é considerado um nome inválido, mas Zend_Controller_PluginInterface ou Zend_Controller_Plugin_PluginInterface seriam nomes válidos. Embora esta regra não seja obrigatória, ela é fortemente recomendada, já que provê uma boa pista visual aos desenvolvedores sobre quais arquivos contém interfaces em vez de classes. Esta convenção de nomenclatura é nova na versão 1.9.0 do Zend Framework. Classes de datas anteriores a esta versão podem não seguir esta regra, mas serão renomeadas no futuro a fim de obedecê-la. Veja a seção anterior para informações sobre a razão da mudança. Nomes de arquivos Para todos os outros arquivos, somente caracteres alfanuméricos, underscores e hifens são permitidos. Espaços são estritamente proibidos. Qualquer arquivo que contenha código PHP deve terminar com a extensão ".php", com a notável exceção de scripts de view. Os exemplos a seguir mostram nomes de arquivo aceitáveis para classes do Zend Framework: Nomes de arquivos devem mapear nomes de classes, como descrito acima. Funções e métodos Nomes de funções devem conter somente caracteres alfanuméricos, não sendo underscores permitidos. Números são permitidos mas desencorajados na maioria dos casos. Nomes de funções devem sempre começar com letra minúscula e, quando consistir de mais de uma palavra, a primeira letra de cada palavra deve ser maiúscula. Esta formatação é comumente chamada de "camelCase". A utilização de verbos é geralmente encorajada, devendo os nomes de funções ser tão verbais quanto prático a fim de descrever de forma clara seu propósito e comportamento. Estes são exemplos de nomes aceitáveis de funções: Para programação orientada a objetos, acessores de variáveis estáticas ou de instância devem sempre ser prefixados com "get" ou "set". Ao implementar padrões de design (“design patterns”), como o singleton ou o factory, o nome do método deve conter o nome do padrão onde prático a fim de descrever claramente seu comportamento. Para métodos de objetos que são declarados com o modificador "private" ou "protected", o primeiro caractere do nome do método deve ser um underscore. Esta é a única aplicação aceitável de um underscore em um nome de método. Métodos declarados como "public" nunca devem conter um underscore. Funções em escopo global (também chamadas de "funções flutuantes") são permitidas mas desencorajadas na maioria dos casos. Considere encapsular estas funções em uma classe estática. Variáveis Nomes de variáveis devem conter somente caracteres alfanuméricos, não sendo underscores permitidos. Números são permitidos mas são desencorajados na maioria dos casos. Para variáveis de instância declaradas com o modificador "private" ou "protected", o primeiro caractere do nome da variável deve ser um underscore. Esta é a única aplicação aceitável de um underscore em nome de variável. Variáveis-membras declaradas com "public" nunca devem começar com um underscore. Assim como nomes de funções (veja seção 3.3), nomes de variáveis devem sempre começar com uma letra minúscula e seguir a convenção "camelCase". A utilização de verbos é encorajada, ou seja, variáveis devem sempre ser tão verbais quanto prático para descrever os dados que o desenvolvedor pretende armazenar nelas. Nomes concisos de variáveis como "$i" e "$n" são desencorajados para todos os contextos de laço, exceto os menores. Se um loop contém mais de 20 linhas de código então as variáveis de índice devem ter nomes mais descritivos. Constantes Constantes devem conter tanto caracteres alfanuméricos quanto underscores. Números são permitidos. Todas as letras usadas em um nome de constante devem ser maiúsculas, enquanto todas as palavras devem ser separadas por underscores. Por exemplo, EMBED_SUPPRESS_EMBED_EXCEPTION é permitido enquanto EMBED_SUPPRESSEMBEDEXCEPTION não. Constantes devem ser definidas como membras de classe com o modificador "const". Definir constantes em escopo global com a função "define" é permitido mas fortemente desencorajado. 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: ]]> 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: 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: 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: Por consistência, esta forma não é permitida: 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: 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 "=": 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: É 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: 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: 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: '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. '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: Classes que estendem outras classes ou que implementam interfaces devem declarar suas dependências na mesma linha, quando possível. 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. 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. 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: 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: O único mecanismo de passagem de parâmetro permitido em uma declaração de método é a passagem por referência. 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. 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: 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: 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. 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. 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": 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. O construtor default nunca deve ser omitido de uma expressão switch. 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: 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: 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: