El estilo de programación son las series de convenciones seguidas al desarrollar código fuente en un determinado lenguaje de programación.
Esta guía describe las convenciones usadas para el desarrollo en PHP aunque se pueden extender perfectamente a otros lenguajes con sintaxis similar.
El estilo de programación descrito en esta guía es sólo una recomendación, aunque se insta fervientemente a su utilización para garantizar que todo el código fuente generado por varias personas tenga un estilo similar con lo que se consigue que las revisiones de código entre los distintos programadores sea mucho más sencilla.
Dentro de los estilos más genéricos de programación, se usará el estilo BSD KNF (BSD Kernel Normal Form) y se parece mucho al estilo K&R.
Para más información véase la Wikipedia.
No se deberían usar los siguientes estilos de programación:
Es la práctica de escribir frases o palabras compuestas eliminando los espacios y poniendo en mayúscula la primera letra de cada palabra.
Similar al Camel Case sólo que la primera letra de la primera palabra es también en minúscula. Por ejemplo, la frase "generar datos aleatorios" pasada a lowerCamelCase sería "generarDatosAleatorios".
Similar al Camel Case siendo la primera letra de la primera palabra en mayúscula. Por ejemplo, la frase "generar datos aleatorios" pasada a UpperCamelCase sería "GenerarDatosAleatorios".
Las palabras reservadas del lenguaje así como las construcciones que se asimilan a funciones
(array(), list(), etc.) se escribirán todas en minúsculas.
La indentación o sangrado debe ser hecha mediante tabulaciones y no se deben insertar espacios. Se recomienda que el tamaño de las tabulaciones sea de 4 espacios aunque esto queda a opción del programador.
Las variables usadas en cualquier aplicación deben tener nombres que las identifiquen, es decir, nombres como "a", "b" o "c" no se deberían usar sino que deberían tener un nombre coherente con con lo que contienen. En el siguiente ejemplo los nombres de las variables son cortos por lo que no se identifica su significado:
$a = 0, $b = 0, $c = 0; if($a > 10 && $b > 20 && $c > 30) { return true; } else { return false; }
Este ejemplo debería ser:
$hora = 0, $minuto = 0, $segundo = 0; if($hora > 10 && $minuto > 20 && $segundo > 30) { return true; } else { return false; }
Sólo en el caso de que la variable sea lo demasiado genérica para no tener un nombre concreto (por ejemplo el índice de un bucle) ésta se declarará con el nombre de "i" siguiendo el orden alfabético en caso de varios bucles anidados ("i", "j", "k",...).
Los nombres largos de las variables se escribirán en lowerCamelCase.
Existen variables que no son variables de tipo simple sino que son compuestas, por ejemplo, los arrays y las estructuras.
En PHP no existen estructuras ya que gracias a los arrays asociativos no son necesarias.
Para crear un array vacío, la sintaxis es la estándar:
$miArray = array();
Para crear un array monodimensional, la sintaxis sería la misma que la anterior:
$miArray = array(1,2,3,4,5);
Para crear un array multidimensional (o asociativo), éste se pondría en líneas separadas e indentadas una tabulación respecto al nombre de la variable que lo contiene de la siguiente forma:
$miArrayMultidimensional = array( 1 => "primero", 2 => "segundo", 3 => "tercero", 4 => "cuarto" );
En caso de ser un array asociativo, para mejorar la legibilidad, se debería indentar el valor de cada entrada a la misma altura de la siguiente forma:
$miArrayAsociativo = array( "Barcelona" => 08000, "Guadalajara" => 19000, "Leon" => 24000, "Madrid" => 28000, "Santa Cruz de Tenerife"=> 38000 ); $miArrayVariado = array( "primero" => 1, "segundo" => array( "hora" => 16, "minuto" => 58, "segundo" => 16 ), "tercero" => null );
En caso de que se puedan declarar estructuras del estilo de C, serían de la siguiente forma:
struct MiStruct { int valor1; int valor2; float valor3; char* nombre; };
Los nombres de las funciones serán en lowerCamelCase. Los delimitadores del cuerpo
de la función, en caso de que sean llaves ({ y }) estarán: el de apertura en la misma
línea que la declaración de la función separado por un espacio (aunque se permite que
esté en la siguiente línea). La llave de cierre debe estar en una línea a parte y no debe
haber más código que la propia llave de cierre. Por ejemplo:
function getUserName($parametros) { // código }
En caso de que en las funciones se declare el tipo devuelto, este estará en una línea a parte encima del nombre de la función.
bool getUserName(void* parametros) { // código }
En caso de que haya muchos parámetros, estos estarán en múltiples líneas indentados con tabulaciones y espacios hasta coincidir en la misma columna que el primer parámetro. Por ejemplo:
function getDataFromDB($param1, $param2, $param3, $param4) { // código }
Los nombres de los parámetros, igual que los nombres de las variables, deben ser nombres concretos del tipo de parámetro en cuestión.
Dentro de la implementación de la función sólo debería haber un return aunque esta regla
que se puede omitir siempre y cuando se mejore la legibilidad del código así como el rendimiento.
Los nombres de las clases deben estar escritos en UpperCamelCase. La indentación de las mismas debe ser de una tabulación con respecto al margen izquierdo mientras que los campos y los métodos deben estar indentados una tabulación con respecto a la clase.
La implementación de los métodos deben estar indentadas con una tabulación respecto al nombre del método. El resto de estilos es similar al de las funciones normales.
Dentro de las clases, los métodos deben estar separados por un retorno de carro entre sí y por un retorno de carro tanto del inicio y final de la clase como de las propiedades.
Las propiedades similares pueden estar agrupadas (sin separar con retornos de carro) pero no en la misma línea, mientras que las propiedades que no tengan relación deben estar separadas por un retorno de carro igual que los métodos.
Si un método o propiedad tiene documentación, se aplica la misma normal de separación.
Tanto la clase como los métodos y propiedades deben estar documentados. Así mismo, en la clase deben existir los elementos @author y @version de la documentación aunque se pueden incluir más como @internal, @since, etc.
En caso de que un clase extienda otra o implemente una interfaz, la extensión debe estar en la misma línea que el nombre de la clase.
Los modificadores de clase o de método, como abstract, static, etc., también
deben estar en la misma línea que el nombre que modifican.
Los nombres de las interfaces, por convención, deben comenzar por "I" mayúscula, por ejemplo: IConfig.
<?php /** * Documentación para la clase 'MiClaseDeEjemplo'. * * @author Diego Lago <beosman@gmail.com> * @version 0.1 2008-09-11 */ class MiClaseDeEjemplo extends MiClaseBase implements MiInterface { private static $campo1; private $campo2; static function miMetodo1() { } /** * Documentación para el método 'miMetodoDos'. * * @param mixed $param1 El primer parámetro. * @param mixed $param2 El segundo parámetro. * * @return mixed Valor de retorno. */ function miMetodoDos($param1,$param2) { } } ?>
Las constantes dentro de una clase se deben declarar todas en mayúsculas y las diferentes palabras que la compongan separadas por barras bajas (_). Por ejemplo:
const ESTO_ES_UNA_CONSTANTE = 0;
Otra forma también permitida aunque no recomendada es que las constantes estén escritas en UpperCamelCase pero que siempre comiencen por la letra "k" minúscula. Por ejemplo:
const kEstoEsUnaConstante = 0;
En caso de que haya varias constantes dentro de la clase, las que estén relacionadas deben tener los valores a la misma altura. Por ejemplo:
const ENGINE_MSSQL = "mssql"; // Microsoft SQL const ENGINE_MYSQL = "mysql"; // MySQL const ENGINE_PGSQL = "pgsql"; // Postgre SQL const ENGINE_FIREBIRD = "firebird"; // Firebird const ENGINE_ORACLE = "oci"; // Oracle Call Interface const ENGINE_ODBC = "odbc"; // Open Database Connectivity const ENGINE_SQLITE = "sqlite"; // SQLite
Los comentarios de las constantes también deberían estar alineados verticalmente.
En el caso de que existen varias constantes que no estén relacionadas, estas deberían estar separadas por una línea en blanco.
Las variables de las clases, al igual que las variables normales, deben estar escritas en
lowerCamelCase. Además, es recomendable declarar cada variable en una línea diferente
junto con su modificador de acceso (public, private, protected). Por ejemplo:
public $primeraVariable; private $unaVariablePrivada; protected $variableProtegidaParaMisSubclases;
En caso de que existan varias variables relacionadas que requieran un valor de inicialización, éstas, al igual que las constantes, deben tener dichos valores alineados verticalmente.
Los métodos de las clases, al igual que las funciones normales, deben estar escritos en lowerCamelCase. La forma de escribir los parámetros y el cuerpo es la misma que para las funciones normales.
Además, a las funciones hay que incorporarles su modificador de acceso aunque, en el caso de que sean públicas, no es necesario incluirlo. Por ejemplo:
private function getRealName() { // código }
Los operadores, como +, +=, -, -=, *,
*=, /, /=, %, %=, =, ==,
===, !=, >, >=, >>,
<, <=, <<, =>, &,
&&, |, ||, ?,
etc., deben escribirse con espacios a ambos lados. Por ejemplo:
$miVariable = $otraVariable + 1 - ($pi * 3);
Una excepción a esta regla son los operadores unarios ++ y -- donde no es necesario (ni recomendable) poner
un espacio antes (o después, según sea de postincremento o preincremento) de la variable que modifican.
El siguiente ejemplo sería correcto:
$miVariableNumerica++;
Estas reglas de separación son útiles, por ejemplo, cuando existen varias expresiones que pueden dar lugar a ambigüedad:
$a = $b+++++$c;
La expresión anterior, si se siguen las directrices de separación de operadores, tendría la forma:
$a = $b++ + ++$c;
De esta forma el programador distingue perfectamente lo que hace la expresión anterior.
Cuando se comprueba una expresión y esta devuelve un valor booleano, es preferible hacerlo en una
operación lógica booleana en lugar de introducirlo en una estructura de control de tipo if.
Por ejemplo, en el siguiente código:
if($a > 100 && $b < 50 && $c != 4) { return true; } else { return false; }
Es más recomendable hacerlo de la siguiente forma:
return ($a > 100 && $b < 50 && $c != 4);
Esto es por mera sintaxis ya que el compilador genera el mismo código objeto para ambas expresiones.
Siempre que sea posible, se deberán utilizar valores booleanos en lugar de números, es decir, si
una variable es booleana, no se le debe asignar "0" para false y "1" para true.
Se le deben asignar las construcciones del lenguaje true y false.
Las estructuras de control son aquellas instrucciones del lenguaje que controlan el flujo de ejecución, es decir, sentencias que deciden qué ejecutar en cada caso, bucles de instrucciones, etc.
La sentencia if debe escribirse de la siguiente forma:
if y el primer paréntesis es recomendable que haya un espacio.if y la condición
separada del último paréntesis por un espacio.if.else, ésta junto con la llave de apertura del siguiente bloque de código, deben
ir en la misma línea que la llave de cierre del bloque de código del if.if y la llave de apertura del bloque del else
else debe ir a la misma altura de indentación que el if.if consecutivos, se puede optar por la forma separada else if o por la
forma junta elseif.elseif sigue las mismas reglas que la parte del else.Un ejemplo de esta sentencia sería la siguiente:
if ($condicion) { // código } else if ($miVariable >= 100) { // código } elseif ($condicion || $miVariable < 100) { // código } else { // código }
La sentencia switch debe escribirse de la siguiente forma:
switch y el paréntesis de la variable es recomendable que haya un espacio aunque no es necesario.switch separada por un espacio respecto del paréntesis de cierre.case deben ir indentados una tabulación respecto al switch.case debe ir en líneas distintas a las del case e indentado una tabulación respecto al
case y dos tabulaciones respecto al switch.case compartan el mismo código, éstos deben estar en líneas separadas como si fuesen independientes.break de cada case está al mismo nivel de indentación que el código dentro del case
porque no es otra cosa que código referido a dicho case.default y ésta debe ser la última.default lleve break ya que es la última del bloque.switch.
Un ejemplo de un bloque switch sería el siguiente:
switch ($valor) { case 1: // código break; case 2: // código break; case 3: case 4: // código break; default: }
La sentencia for debe escribirse de la siguiente forma:
for y el paréntesis de apertura de las condiciones es recomendable que haya un espacio.for separada por un espacio respecto del último paréntesis.for debe estar indentado respecto al for con una tabulación.for.
Un ejemplo de un bloque for sería el siguiente:
for ($i = 0; $i < 100; $i++) { // código }
La sentencia foreach sigue las mismas reglas que la sentencia for:
foreach ($array as $indice => $valor) { // código }
Sólo se debe poner el índice en el caso de que se vaya a usar.
La sentencia while se escribe de la siguiente forma:
while y el paréntesis de apertura de la condición debería existir un espacio.while y la condición separada
un espacio del paréntesis de cierre de la condición.while.while.
Un ejemplo de escritura de la sentencia while sería el siguiente:
while ($condicion) { // código }
La sentencia do while se escribe de la siguiente forma:
do debe estar en la primera línea junto con la llave de apertura de código separadas por un espacio.do.while a la misma altura de indentación que la palabra do.while debe estar separada un espacio de la llave de cierre de bloque.while debería estar un espacio separada de la palabra while.
Un ejemplo de un bloque do while sería el siguiente:
do { // código } while ($condicion);
El operador ternario es una forma simplificada de escribir una sentencia if.
El operador ternario se debería escribir siempre en una misma línea y encerrado entre paréntesis
(aunque no es estrictamente necesario). Hay que seguir las reglas de los operadores.
Tanto la condición como los bloques de código deben ser lo más pequeños posible ya que sino este
operador estaría demasiado ofuscado. En caso de que sean demasiado grandes se debería usar una sentencia if.
Un ejemplo de operador ternario sería el siguiente:
return ($valor >= 5 ? "aprobado" : "suspenso");
Las excepciones son una forma de propagación de errores dentro de la aplicación. Las excepciones funcionan de forma similar a los objetos por lo que su guía de estilo no varía.
Para cada categoría de errores se debería crear un tipo nuevo de excepción que bastaría
con que extienda una excepción ya conocida o la excepción base (class Exception).
Las excepciones se lanzan con el mismo nivel de indentado que la llamada a una función:
throw new MiExcepcion("Mensaje de la excepción");
La forma de coger las excepciones antes de que se extiendan a toda la aplicación y la
hagan parar es mediante la sentencia try/catch. Esta sentencia es un aglutinador de trozos de
código que son susceptibles de lanzar alguna excepción y sirven para capturarla y evitar
su propagación actuando en consecuencia.
La forma de capturar una excepción es la siguiente:
try { functionQueLanzaExcepcion(); } catch(Exception $e) { // tratamos la excepción aunque la podemos volver a // lanzar con un throw $e }
Dentro de la sentencia catch se puede poner cualquier tipo de excepción. Además, también
pueden existir varios catch dentro del mismo bloque de código para capturar y tratar de
forma distinta varios tipos de excepciones. Hay que recordar que el orden de captura debe
ser el inverso al orden en el árbol de herencia de las excepciones.
La llave de apertura del try debe estar en la misma línea que el propio try. La llave de
cierre del try (o de otro catch), el catch y la llave de apertura del catch deben estar en
la misma línea. La llave de cierre del último catch debe estar en una línea diferente.
En caso de existir la sentencia finally, ésta tiene el mismo estilo que el catch:
try { functionQueLanzaExcepcion(); } catch(MyException $e) { // tratamos una excepción que hereda de Exception } catch(Exception $e) { // ahora tratamos la excepción base } finally { // este código siempre se ejecuta }
Los comentarios son la forma de aclarar el funcionamiento del código desarrollado así como generar la documentación específica de la API por lo que dichos comentarios son necesarios a lo largo de todo el desarrollo.
Existen dos tipos de comentarios: los comentarios de aclaración del código y los comentarios de documentación.
Este tipo de comentarios se escribe en el medio del código para aclarar su funcionamiento. El comentario en
cuestión se debe hacer en la línea inmediatamente superior a la línea de código fuente que se desea aclarar y
se deben utilizar los comentarios de doble barra (//) de la siguiente forma:
// se comprueba por si la instancia es null if($instancia === null) { $error = "La instancia es NULL.; }
En caso de que la aclaración sea los suficientemente corta, se puede incluir en la misma línea de código. El punto y coma debe estar separado dos espacios de la primera barra invertida y el texto del comentario debe estar separado un espacio de la segunda barra:
$i++; // incrementamos la variable
En caso de que el comentario aclaratorio sea bastante largo, se deben usar los comentarios multilínea con apertura
(/*) y cierre (*/). El uso de asteriscos en cada inicio de línea es opcional aunque recomendable teniendo en
cuenta que muchos editores los añaden automáticamente:
/* * Este es un comentario multilínea para aclarar el * funcionamiento de una o varias líneas de código que * son difíciles de entender por la complejidad del * tratamiento de los datos. */ foreach($datos as $indice => $dato) { if(validarDato($dato)) { enviarDato($indice,$dato); } }
El nivel de indentación de los comentarios debe ser el mismo que el de la línea que comentan y no debería haber ninguna línea adicional entre la última línea del comentario y la línea de código fuente que comentan. Además, entre los asteriscos y el texto debe haber un espacio.
Los comentarios de documentación son comentarios multilínea con un formato especial y con palabras clave interpretadas por el generador de la documentación.
Estos comentarios se utilizan para la generación de la documentación del API del código fuente, tanto pública (hacia otros programadores) como privada (hacia los programadores de la aplicación).
Los comentarios de documentación comienzan por la apertura de un comentario multilínea seguido de un asterisco. Cada nueva línea del comentario debe ser precedida por un asterisco y su indentación debe ser la misma que el primer asterisco (no la barra oblícua) de la línea de apertura del comentario. El final de la línea debe estar indentada a la misma altura que las líneas intermedias.
Este tipo de comentario es igual que el comentario multilínea mencionado anteriormente añadiéndo un asterisco a la primera línea:
/** * Comentario de documentación de clases y funciones. * * Estos comentarios pueden llevar etiquetas especiales * con significado dentro de la documentación general: * * @author Diego Lago <beosman@gmail.com> * @version 0.2 2008-09-02 */
Los comentarios de documentación deben comentar las clases, los métodos y las funciones. Además, es recomendable comentar las variables de las clases.
Dentro de los comentarios de documentación, como se ha podido comprobar en el ejemplo anterior, pueden (y deben) existir etiquetas especiales que son interpretadas por el generador de documentación. Todas estas etiquetas comienzan por @ (arroba) y pueden ser las siguientes:
@author: Indica el autor de la clase, función, etc.@copyright: Indica la información del copyright de un archivo o clase.@deprecated: Indica que un elemento es antiguo y no se debe usar.@example: Indica un archivo de ejemplo.@global: Documenta una variable global o su uso.@internal: Indica que es documentación interna.@license: Indica la licencia del archivo o clase.@link: Indica un enlace a otro elemento de documentación.@method: Indica la implementación de un método “mágico” de la clase (PHP).@param: En una función indica el tipo de parámetro y sus posibles valores.@property: Indica la implementación de una propiedad “mágica” de una clase (PHP).@return: En una función indica el tipo de retorno de una función y sus posibles valores.@see: Indica que se debe ver además otro elemento de la documentación.@since: Indica desde qué versión está disponible este elemento.@throws: En una función indica el tipo de excepciones que puede lanzar.@todo: Indica cambios futuros en el código.@var: Documenta una variable de una clase.@version: Indica la versión de la clase, archivo o función.Cada una de estas etiquetas tiene una sintaxis específica por lo que se debe examinar la documentación del generador de documentación para ver su sintaxis específica.
Esta documentación, en caso de generarla, se genera en HTML por lo que se pueden incluir (y es recomendable) etiquetas HTML dentro de la propia documentación.
Estas reglas, como se comenta en el inicio de esta guía, son sólo opcionales aunque es muy recomendable su cumplimiento para que las distintas revisiones del código por distintas personas no sean demasiado complicadas y todos los integrantes del proyecto estén familiarizados con el mismo tipo de codificación.
Así mismo, en caso de seguirlas, estas reglas no son estrictas por lo que se puede relajar en la medida de lo posible para adaptarse a todos los estilos de programación de los distintos integrantes del grupo de trabajo.