Herramientas de usuario

Herramientas del sitio


ingenieria:estandard-de-codificacion

Estandard de Codificación

Las reglas aquí descritas son una guía para la obtención de un código legible y conciso, siempre debieran seguirse, no obstante pudieran violarse si ello permitiera una mayor legibilidad y claridad del código fuente.


Identación y longitud de línea

Usar identación de 1 tabulación por nivel.

Las líneas deberan tener una longitud máxima de 80 caracteres. Se permiten excepciones cuando esta regla valla en detrimento de la legibilidad del código.


Documentación del código y comentarios

Las definiciones de clases, propiedades de clase, métodos y funciones deben tener su correspondiente DocBlock de PHPDoc. Los algoritmos complejos deben documentarse con comentarios de una sola línea o de múltiples líneas si se da una explicación general.

/**
 * @param string $prop_slug El slug del campo buscado
 * @param mixed $prop_value El nuevo valor del campo
 *
 * @throws ProfileNotBoundToUserException Si el perfil no está vinculado
 *   a un usuario
 * @throws InvalidPropertyException Si la propiedad buscada no es un campo
 *      dinámico del perfil
 *
 * @return boolean
 */
function __set($prop_slug, $prop_value) {
    // Verificar que el perfil está en modo vinculado a usuario
    if (!$this->isBoundToUser())
        throw new ProfileNotBoundToUserException();

    // Buscar el objeto que contiene el valor actual del campo y cambiarlo
    foreach ($this->fieldValues as $fv) {
        if ($fv->getFieldDescriptor()->getSlug() === $prop_slug) {
            if (is_string($prop_value))
                $prop_value = $fv->getFieldDescriptor()->stringToValue($prop_value);

            $fv->setValue($prop_value);
            return true;
        }
    }
    /*
     * Si no se encuentra se crea
     */

    // Obtener el descriptor del campo buscado
    $fd = $this->getFieldDescriptor($prop_slug);

    // Verificar que el descriptor existe
    if($fd === null)
        throw new InvalidPropertyException(sprinf("The profile does not have a field named '%s'", $prop_slug));

    if (is_string($prop_value))
        $prop_value = $fd->stringToValue($prop_value);

    // Crear el objeto que representa el valor del campo
    $fv = new ProfileFieldValue($this->user, $this, $fd, $prop_value);
    // Adicionar el valor al perfil
    $this->addProfileFieldValue($fv);

    return true;
}
</file>

Los comentarios de una línea pueden aparecer encima o al lado de la sentencia que documentan teniendo en cuenta la regla para el largo de las líneas. Si aparecen encima pueden dividirse en varias líneas y, si aparecen al lado deben iniciarse preferiblemente despues de una columna múltiplo de 4 y alineados entre sí si se comentan varias líneas consecutivas.

<code>$arr = array(1, 2, 3);  // Estos comentarios comienzan en la columna 25 (24 + 1)
$v1  = 10';   // y están alineados entre sí

$p += $v1 + $arr[0];    // Otro comentario

Espacios y líneas en blanco

Se deja un espacio en blanco:

  • Entre una estructura de control y los paréntesis de la condición. [línea 4]
  • Entre operandos y operadores binarios. [líneas 5, 6, 8 y 15]
  • Entre una estructura de control o definición de método o función y la llave de apertura del bloque que define. [líneas 3 y 4]
  • Entre los parámetros de la definición o llamada a una función o método. [líneas 3, 5 y 16]
  • Entre los caracteres de slash “” y los comentarios de una línea. [líneas 5, 6 y 8] ==== No se deja un espacio en blanco: ==== * Entre un operador unario y su operando. [línea 4] * Entre los operandos del operador flecha “→”. [línea 16] * Entre el nombre de un método o función y los paréntesis de definición de parámetros. [línea 3] * La llamada a un constructor, método, o función y la lista de parámetros. [líneas 15 y 16] * Una variable de tipo array y los corchetes que especifican el índice a acceder. [línea 8] ==== Se deja una línea en blanco: ==== * Después del cierre de un bloque de código. [líneas 7, 10 y 14] * Entre agrupaciones de sentencias altamente cohesivas. [línea 7] ==== Ejemplo: ==== <code>1. class MiClase 2. { 3. public function f1($p1, $p2, $p3) { 4. if (!$p2) { 5. $arr = array(1, 2, 3); Definición de variable

6. $v1 = 10'; Definición de variable 7. 8. $p += $v1 + $arr[0]; Otro tipo de sentencias 9. } 10. 11. retrun $p; 12. } 13. } 14. 15. $obj = new MiClase(); 16. $obj→f1(5, 6, 7); </code>


''Alineamientos''

En el caso de un bloque de asignaciones relacionadas se pueden alinear los signos de igualdad (=) .

$short = foo($bar); $long_variable = foo($baz);

Lo mismo se aplica a las definiciones de arreglos.

<code> $some_array = array(

''  'a'    => 'foobar',
  'foo'  => 'bar',
  'spam' => 'ham',

''

);

Las llamadas a funciones se pueden dividir en varias líneas. Los parámetros se identan 1 nivel respecto a la línea de la función a la que pertenecen.

Los paréntesis de cierre se escriben en su propia línea identada al nivel de la línea donde fueron abiertos.

$this->someObject->subObject->callThisFunctionWithALongName(
    $parameterOne, $parameterTwo,
    $aVeryLongParameterThree
);

Lo mismo es válido para funciones anidadas y definición de arreglos.

$this->someObject->subObject->callThisFunctionWithALongName(
    $this->someOtherFunc(
   $this->someEvenOtherFunc(
            'Help me!',
            array(
                'foo'  => 'bar',
                'spam' => 'eggs',
            ),
            23
        ),
        $this->someEvenOtherFunc()
    ),
    $this->wowowowowow(12)
);

Las llamadas concatenadas a funciones pueden dividirse en varias líneas, indentando cada línea subsecuente y comenzandola con el operador flecha “→”.

$someObject->someFunction("some", "parameter")
    ->someOtherFunc(23, 42)
    ->andAThirdFunction();

Apertura y cierre de llaves

Salvo en la definición de una clase, las llaves deben abrir al lado de la estructura a la que petenece, separada por un espacio.

class MiClase
{
    public function f1($p) {
   if ($p) {
        ;
        }
    }
}

Estructuras de control

  • Los bloques de las estructuras de control deberán encerrarce entre llaves incluso cuando no sea necesario, para mejorar la legibilidad del código

if

if ((condition1) || (condition2)) {
    action1;
} elseif ((condition3) && (condition4)) {
    action2;
} else {
    defaultaction;
}

En el caso de condiciones muy largas o complejas pueden dividirse en varias líneas

if (($condition1 || $condition2)
    && $condition3
    && $condition4
) {
    //code here
}

La 1ra condición puede alinearse al resto

if (   $condition1
    && $condition2
    && $condition3
) {
    ;
}

Las condiciones también pueden expresarse como variables para hacerlas más legibles

$is_foo = ($condition1 || $condition2);
$is_bar = ($condition3 && $condtion4);
if ($is_foo && $is_bar) {
    // ....
}

switch

switch (condition) {
    case 1:
   action1;
        break;

    case 2:
        action2;
        break;

    default:
        defaultaction;
    break;
}

for

for ($i = 1; $i <= 10; $i++) {
     print $i;
}

foreach

foreach ($a as $v) {
   ;
}

foreach ($arr as $key => $value) {
   ;
}

while

while (list(, $value) = each ($arr)) {
    ;
}

do..while

do {
     ;
} while ($condition);

Operadores ternarios

$a = $condition ? $foo : $bar;
$b = $condition1 && $condition2
    ? $foo : $bar;

$c = $condition3 && $condition4
    ? $foo_man_this_is_too_long_what_should_i_do
    : $bar;

Estilos de nomenclatura

Deben tenerse en cuenta las siguientes consideraciones generales:

  • Los nombres deben escribirse en inglés
  • Los nombres deben ser cortos
  • Solo la 1ra letra de unas siglas debe ir en mayúsculas
  • Bien: class HtmlParser, function getHtmlStatistics()
    Mal: class HTMLParser, function getHTMLStatistics()

Clases

UpperCamelCase: DownloadAgent, HtmlParser

Funciones y métodos

lowerCamelCase: downloadFile, parseHtml

Constantes

UPPER_UNDERSCORE_CASE: DB_DATASOURCE_NAME, DEFAULT_VALUE

Propiedades, parámetros de funciones y variables

lower_underscore_case: $first_name, $html_code

(Considerar la posibilidad de utilizar la notación $lowerCamelCase para algunos de estos elementos por ser más comoda de teclear y más económica en espacio)

Parámetros de salida

La única función de parámetro de salida es devolver algún resultado adicional. La función o método que lo declare debe garantizar su inicialización. No se espera que un parámetro de salida aporte alguna información relevante a la lógica de la función o método que lo declara. No tiene sentido la existencia de un parámetro de salida si la función o método que lo declara no devuelve un resultado mediante 'return'.

Este tipo de parámetro siempre será pasado por referencia, deberá llevar el postfijo '_OUT' y se ubicará al final de la lista de parámetros.

En el DocBlock, su tipo será null y su descripción comenzará con '(Parámetro de salida) Devuelve'. El bloque de parámetros de salida se separa del resto de los parámetros por una línea en blanco.

/*
 * @param type $param1 ...
 * @param type $param2 ...
 *
 * @param null $output_param_OUT (Parámetro de salida) Devuelve ...
 * ...
 * @return ...
 */
public function mf($param1, $param2, &$output_param_OUT) {
    // ...
    $output_param_OUT = 'valor_a_devolver';
    // ...
    return $some_value;
}

Parámetros de referencia

Una función o método que declare un parámetro por referencia puede cambiar (y probablemente cambiará) el valor de dicho parámetro y estos cambios estarán disponibles para el llamador de la función o método.

Este tipo de parámetro siempre será pasado por referencia, deberá llevar el postfijo '_REF' y se ubicará al final de la lista de parámetros pero antes de cualquier parámetro de salida. En el DocBlock, su descripción comenzará con '(Parámetro de referencia)'.

/*
 * ...
 * @param type $common_param ...
 * @param type $reference_param_REF (Parámetro de referencia) Listado de ...
 *
 * @param null $output_param_OUT (Parámetro de salida) Devuelve ...
 *
 * @return ...
 */
public function mf(/*type_hint*/ $common_param, /*type_hint*/ &$reference_param_REF, &$output_param_OUT) {
    // ...
    array_push($reference_param_REF, 'nuevo_valor');
    $output_param_OUT = 'valor_a_devolver';
    // ...
    return $some_value;
}

Miembros de clase protegidos y privados

Se precede con un guión bajo aquellos miembros de una clase que sean de uso interno exclusivamente. Esto abarca a métodos protegidos, métodos privados, constantes que no deban ser usadas fuera de la clase o sus descendientes y propiedades privadas y propiedades protegidas carentes de métodos accesores.

Se excluyen de esta regla las propiedades protegidas que puedan ser accedidas por métodos accesores (getters, issers, setters).

class MiClase
{
    const MAX_VALUE = 500;
    const _CACHE_SIZE = 1000;

    protected $values;

    private $_value_cache;

    public function parseHtmlCode($html_code) {
        // ...
    }

    protected function _doInitialLoad() {
        // ...
    }

    public function getValues() {
        // ...
    }

    public function addValue($value) {
        // ...
    }
}

Estructura de una clase

Las declaraciones de los miembros de una clase se harán en el siguiente orden:

  • Constantes
  • Propiedades estáticas
  • Propiedades de instancia
  • Métodos estáticos
  • Constructor
  • Métodos mágicos
  • Métodos “comunes”
  • Accesores (getters, issers, setters)

Dentro de cada uno de estos bloques las declaraciones se priorizan según la visibilidad en el orden:

  • Públicos
  • Protegidos
  • Privados
class MiClase
{
    const MAX_VALUE = 500;
    const _CACHE_SIZE = 1000;

    /*
     * DocString...
     */
    protected $values;

    /*
     * DocString...
     */
    private $_value_cache;

    public function __construct($html_code) {
        // ...
    }

    public function __toString() {
        // ...
    }

    public function doSomething() {
        // ...
    }

    protected function _doInitialLoad() {
        // ...
    }

    public function getValues() {
        // ...
    }

    public function addValue($value) {
        // ...
    }
}
ingenieria/estandard-de-codificacion.txt · Última modificación: 2016/01/05 23:15 (editor externo)