Algunas pautas de programación

Creo que es importante desarrollar con estándares de código sin importar si el proyecto es de un único desarrollador o si es en equipo. Los estándares permiten que el código que desarrollamos sea de una mejor calidad, que el mantenimiento de nuestros programas se vuelva menos complejo, y provoca que baje la tasa errores ingenuos. He querido hacer un resumen del estándar de codificación de Zend Framework para PHP.

Estilo de código

  • Siempre utilizar la etiqueta inicial de PHP de forma completa ("<?php") para empezar con el código. Si el archivo contiene únicamente código PHP, la etiqueta de cierre no es requerida ("?>"), más bien se recomienda omitirla para evitar inyección de espacios en blanco en la respuesta.
  • Se recomienda usar indentación de 4 espacios. Se debe configurar el editor de texto para convertir las tabulaciones a espacios en blanco.
  • Se recomienda que el ancho de una línea de código sea de 80 caracteres o menos. Siendo el tamaño máximo de 120 caracteres.

Strings (cadenas de caracteres)

  • Cuando un string no contiene sustitución de caracteres, debe usar comilla simple como delimitador.

$a = 'Un texto de ejemplo';

  • Cuando un string contiene apóstrofes, se permite delimitar dicho string con "comillas dobles".

$sql = "SELECT `img` FROM `tweets` where `uid` = '1'";

  • La sustitución de variables está permitida en cualquiera de estas dos maneras:

$retweet = "$tweet (via @$user_from)";
$retweet = "{$tweet} (via @{$user_from})";

  • Fragmentos de strings deben de concatenarse (unirse) utilizando el operador punto (".") y se debe dejar un espacio antes y después de dicho operador para mejorar la legibilidad:

$reply = '@paviles' . ' ' . 'Hi, buddy!!';

  • Cuando se concatenan varios fragmentos de texto usando el operador ".", se recomienda partir en varias líneas la sentencia, y así mejorar la legibilidad. Cada línea debe iniciar con un margen de espacios en blanco de manera que el operador "." quede alineado debajo del operador "=" de la primera línea:

$sql = "SELECT `user`, `user_img`, `tweet` " 
     . "FROM `tweets` " .
     . "WHERE `if_active` = 1 "
     . "ORDER BY `date` desc";

Arrays (arreglos)

  • No se permiten los números negativos como índices.
  • Los índices en arreglos de índices  numéricos, pueden inciar con cualquier valor no negativo, pero no se recomienda que inicien con un valor distinto al 0.
  • Para mejorar la legibilidad, se debe agregar un espacio después de cada coma de separación de los índices en la declaración del “array”:

$diasArreglo = array(1, 2, 3, 4, 5, 6, 7);

  • Se pueden hacer declaraciones de los arrays en varias líneas, siempre y cuando los inicios estén alineados (identados) igual:

$mesesArreglo = array(
                      1, 2, 3, 4,
                      5, 6, 7, 8,
                      9, 10, 11, 12,
);

  • Se recomienda hacer la declaración de los arrays asociativos divididos en diferentes líneas. Se recomienda dejar espacio antes y después de los operadores de asignación “=>” y de forma que queden alineados:

$arregloSimple = array(
    'primerIndice'  => 'primerValor',
    'segundoIndice' => 'segundoValor',
);

Clases

  • La llave "{" debe escribirse en la línea siguiente al nombre de la clase ("one true brace"). Debe existir una documentación (PHPDocumentor) para cada clase.
  • El código de la clase debe estar indentado (cuatro espacios).
  • Sólo se permite una clase por archivo PHP.
  • No se recomienda incluir código adicional en archivos de clase. Si se hace, deben distinguirse el código de la clase con dos líneas en blanco.
  • En la medida de lo posible, se deben declarar las dependencias en la misma línea para las clases que extiendan otras clases o interfaces. Si la línea es muy grande, entonces se puede partir la declaración antes de las palabras “extends” e “implements” y se debe indentar.

class ClaseEjemplo
    extends FooAbstract
    implements BarInterface
{
}

  • Si la clase implementa múltiples interfaces y la declaración excede el largo máximo de la línea, se puede partir la declaración después de cada coma, y se debe indentar de modo que los nombres de las interfaces queden alineados:

class ClaseEjemplo
    implements BarInterface,
               BazInterface
{
}

  • Las variables que son miembros de una clase, debe ser listada en la parte superior de la clase, por encima de las declaraciones de cualquier método.
  • No se permite la construcción var. Las variables que son miembro de una clase declaran su visibilidad con los modificadores “private” , “protected” , o “public”. No se aconseja que las variables sean “public”, sino que se recomienda usar métodos de acceso (“set” y “get”).

Funciones y métodos

  • Los nombre de las funciones deben estar de acuerdo a las convenciones de nombrado de Zend Framework.
  • Los métodos dentro de las clases deben declarar su visibilidad usando modificadores como “prívate” , “protected” , o “public”.
  • La llave "{" debe escribirse en la siguiente línea del nombre de la función ("one true brace"). No se permite un espacio entre el nombre de la función y el paréntesis de apertura de los argumentos.
  • No se permiten las funciones con un alcance global.
  • En caso de que los argumentos sobrepasen el tamaño máximo de la línea, se puede partir la declaración:

/**
 * Aquí va la documentación de la clase
 */
class Foo
{
    /**
     * Aquí va la documentación de la función
     */
    public function bar($arg1, $arg2, $arg3,
        $arg4, $arg5, $arg6
    ) {
        // código de la función
        // debe ir indentado.
    }
}

  • No se permite la llamada por referencia a los parámetros.
  • El valor de retorno no debe estar indicado entre paréntesis.
  • Los valores de los argumentos en una función deben separarse por un espacio después de la coma:

tresParametros(1, 2, 3);

  • Al pasar arreglos como argumentos de una función, se puede utilizar el indicador y se pueden separar en varias líneas para facilitar la legibilidad:

tresParametros(array(1, 2, 3, 'bot', 'paviles',
                     $a, $b, $c,
                     56.44, $d, 500), 2, 3);
tresParametros(array(
    1, 2, 3, 'mashups', 'paviles',
    $a, $b, $c,
    56.44, $d, 500
), 2, 3);

Sentencias de control

  • Las sentencias de control basadas en if y elseif  deben tener un único espacio en blanco antes del paréntesis inicial y un único espacio en blanco después del paréntesis final.
  • Los operadores dentro de la condición deben separarse con espacios. Es recomendable usar paréntesis internos para mejorar la agrupación de las expresiones condicionales largas.
  • La llave de inicio "{" debe estar en la misma línea que la condición, mientras que la de cierre "}" debe estar sola. El código dentro de las llaves debe estar indentado:

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

  • Si el largo de la condición es mayor al largo máximo de la línea, y la condición tiene varias cláusulas, se puede partir en varias líneas:

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

  • Toda sentencia "if", "elseif" o "else" debe usar llaves de apertura “{” y cierre “}” sin excepción.
  • Se recomienda utilizar “else if” en vez de "elseif".
  • El código dentro del bloque del "switch" debe estar indentado, y el código dentro de cada "case" estar indentado adicionalmente:

switch ($respuestaPregunta) {
    case 1:
        break;

    case 2:
        break;

    default:
        break;
}

  • Nunca se debe omitir la construcción default en una declaración “switch” .
  • Para evitar errores, si se omite intencionalmente un “break” dentro de un “case”, debe escribirse un comentario justificando el por qué.

Documentación integrada

  • Los "docblocks" (bloques de documentación) deben ser compatibles con el formato de phpDocumentor.
  • Los archivos de clase deben contener un docblock al inicio del archivo y un docblock inmediatamente antes de cada clase.
  • Cualquier archivo con código PHP debe tener un docblock al inicio del archivo, y debe contener al menos las siguiente etiquetas:  Descripción corta del archivo, Descripción larga del archivo, LICENSE, @category, @package, @subpackage, @copyright, @license, @version, @link, @since
  • Toda clase debe contener un docblock con al menos las siguientes etiquetas: Descripción corta de la clase, descripción larga de la clase, @category, @package, @subpackage (opcional), @copyright, @license, @version, @package_version, @link, @since, @deprecated
  • Para las funciones y métodos de los objetos, los docblocks deben contener como mínimo: Una descripción de la función, todos los argumentos de la función y su descripción, los posibles valores de retorno.

Convención de nombres

Archivos

  • Internamente, los archivos PHP no deben contener caracteres de retorno de carro ([0x0D] o [0x0D, 0x0A]). Sino que las líneas deben acabar con el carácter de fin de línea ([0x0A]).
  • Los nombres de los archivos sólo pueden contener caracteres alfanuméricos, guiones bajos (_) y guiones (-). No se permiten espacios en blanco.
  • Archivos que contengan únicamente código php, deben terminar con la extensión.php.

Clases

  • Use nombres de clases cuyos nombres usen como prefijo el nombre la carpeta donde estén contenidas. Por ejemplo, si la clase "Bot" está contenida en una carpeta denominada "Mashups", entonces la clase debe llamarse "Mashups_Bot" y debe guardarse en la ruta "Mashups/Bot.php"
  • Los nombres de clases sólo pueden contener caracteres alfanuméricos. Los números están permitidos en los nombres de las clases, pero no se recomiendan. El guión bajo (_) sólo está permitido como separador de ruta (el archivo "Social/Mashups/Bot.php" contendría a la clase denominada "Social_Mashups_Bot").
  • Si el nombre de la clase se compone de varias palabras, la primer letra de cada palabra debe estar en mayúscula.

Funciones y métodos

  • Los nombres de las funciones sólo pueden contener caracteres alfanuméricos. No se permiten los guiones bajos (_) y no se recomiendan los números.
  • Los nombres de las funciones deben empezar con una letra minúscula, pero cuando se compone de varias palabras, de la segunda palabra en adelante deben iniciar con letra mayúscula (camel case).
  • Los nombres deben ser descriptivos de su propósito y comportamiento.
  • En la OOP, los métodos de acceso a las variables estáticas o instancias, deben ser precedidos por las palabras "get" o "set".
  • Al implementarse un patrón de diseño, como “singleton” o “factory”, el nombre del método debe contener el nombre de dicho patrón para así describir su comportamiento de forma más detallada.
  • Cuando los métodos son declarados con modificadores como "private" o "protected", el primer carácter del nombre de la variable debe ser un guión bajo (_), mientras que los métodos declarados como públicos no deben contener un guión bajo.
  • Se recomienda poner las funciones con un alcance global en una clase estática.

Variables

  • Los nombres de las variables deben contener caracteres alfanuméricos. No se permiten las guiones bajos (_) y no se recomiendan los números.
  • Las variables de instancia que se declaran con los modificadores "private" o "protected", deben tener en el primer carácter un guión bajo (_), mientras que las variables declaradas como "public" no pueden iniciar con un guión bajo.
  • Los nombres de las variables deben empezar con una letra minúscula (camel case).
  • Los nombres de variables deben ser descriptivos de los datos que el programador almacena en ellas. No se aconsejan nombres de variables como " $i " o " $n " excepto para el contexto de loops o ciclos pequeños (menores a unas 20 líneas de código).

Constantes

  • Los nombres de las constantes pueden contener caracteres alfanuméricos, guiones bajos (_) y números.
  • Todas las letras deben estar en mayúscula.
  • La separación entre palabras debe hacerse usando el guión bajo (_).
  • Las constantes deben ser definidas como miembros de una clase usando el modificador "const".
  • No se recomienda definir constantes con alcance global (utilizando la función "define").

Referencias