Guía de buenas prácticas para programar en PHP

Guía de buenas prácticas para programar en PHP

Cursos gratis en tu email Suscribirme

La altísima presencia de PHP en internet ha propiciado que entre la comunidad de programadores haya dos vertientes básicas: detractores y defensores.

Al margen de los argumentos que uno u otro colectivo pueda esgrimir (lenguaje interpretado vs compilado, nomenclatura de funciones, rapidez, etc.), la realidad es que LAMP está detrás de la mayoría de servicios y aplicaciones web.

Desde formación online os presentamos esta guía con veinte consejos y buenas prácticas de programación, con el fin de que vuestro código PHP sea lo más efectivo posible. Recuerda consultar nuestro catálogo de cursos online gratis con miles de opciones para mejorar tus conocimientos.

Buenas prácticas PHP

Tutorial buenas prácticas programación PHP

1. Activar el reporte de errores
error_reporting(E_ALL) es tu amigo. Utilízalo, junto con ini_set('display_errors', 'On'), para ver todas las advertencias del compilador de PHP, saber qué métodos están depreciados, índices inexistentes, etc.
2. No emplear etiquetas cortas
Para que el intérprete de PHP ejecute un código, éste ha de estar delimitado por las etiquetas de apertura y cierre de PHP: <?php ?>. Si en la configuración de PHP de nuestro servidor (archivo php.ini) se permite el uso de etiquetas cortas (<? ?>) el script se ejecutará exactamente igual. Pero, ¿qué ocurre si cambiamos a otro servidor en el que no estén habilitadas? Nuestras páginas dejarán de funcionar como esperamos y, lo que es más grave, puede resultar en que todo nuestro código fuente se imprima por pantalla como texto plano (ya que no habrá sido interpretado), quedando a disposición de cualquier personaje.
3. Operadores de comparación: === vs ==
== (o !=) compara el valor, mientras que === (o !==) compara el valor y el tipo.
Dado que en PHP las variables no tienen un tipo asignado y éste puede cambiar "al vuelo" en tiempo de ejecución, conviene tener en cuenta cómo serán evaluadas las comparaciones en PHP:

<?php
$a = 0;
$b = "0"
$c = false;
var_dump($a == $b); // 0 == 0 -> true
var_dump($a === $b); // 0 == 0 && (integer) == (string) -> false
var_dump($a == $c); // 0 == false -> true

Por otro lado, existen funciones que retornan un número entero. Como el valor lógico de cualquier entero es true, exceptuando el cero, que es false, deberemos tenerlo en cuenta a la hora de evaluar nuestras condiciones. Por ejemplo, la función strpos() busca la posición de la primera ocurrencia de una subcadena dentro de otra:

<php
$cadena = 'formación online';

$buscamos = 'm'; // presente en $cadena
$posicion = strpos($buscamos, $cadena); // $posicion = 3

$buscamos = 'z'; // ausente en $cadena
$posicion = strpos($buscamos, $cadena); // $posicion = false

$buscamos = 'f'; // presente en $cadena
$posicion = strpos($buscamos, $cadena); // $posicion = 0

Por lo tanto, si queremos comprobar la presencia o no de una cadena con strpos() no debemos comparar por valor (==) sino por tipo y valor (===).

4. echo vs print
Estas funciones realizan la misma tarea. Sin embargo, echo es sensiblemente más rápida que print.
5. Concatenación de cadenas, comillas simples(') vs comillas dobles(")
Cuando trabajes con cadenas, evita siempre el uso de comillas dobles. La razón es que PHP analiza el contenido de las comillas dobles en búsqueda de variables que deban ser interpretadas, resultando en un tiempo de ejecución mayor.
Emplea siempre la función echo y concatena las cadenas con comas: echo 'Hola', $nombre, ', ¿qué te trae por aquí? requerirá menos tiempo al compilador que echo 'Hola' . $nombre . ', ¿qué te trae por aquí?'. Por lo visto en el punto anterior, el "peor caso posible" sería print "Hola $nombre, ¿qué te trae por aquí?"
6. Búsqueda de cadenas y patrones case insensitive
La búsqueda de una cadena sin importar mayúsculas/minúsculas (stripos()) es entre un 400% y un 600% más lenta que su equivalente case sensitive, strpos()).
En cuanto a las expresiones regulares, las búsquedas sensibles, preg_match("/$patron/", $cadena), son, como norma, ligeramente más eficaces que su equivalente no sensible: preg_match("/$patron/i", $cadena).
Si las coincidencias se realizan de modo iterativo (dentro de un bucle for, while, foreach), es recomendable convertir a lowercase o uppercase antes y realizar las operaciones en su versión case sensitive.

Cursos de programación
Consulta nuestro directorio para encontrar los mejores cursos de programación. Ver cursos »

7. Convenciones
  • Los nombres de las clases en MixedCase. Ejemplo: ElNombreDeMiClase
  • Los nombres de los métodos en camelCase. Ejempo: nombreDelMetodo()
  • Las constantes siempre en ALL_CAPS. Ejemplo: COLOR_DEFINIDO_PARA_MI
  • Las variables, propiedades y parámetros en camelCase. Ejemplo: $variableEnLaQueAlmacenoAlgo
  • Los métodos y variables que no sean públicos, precedidos por un guión bajo (underscore-prefixed). Ejemplo: $_miPalabraSecreta

Veámoslo en un ejemplo para ilustrar:

<?php  
class MyNewClass{
    const LIMIT_OF_ITERATIONS = 10;
    public $myProperty;
    public $myOtherProperty;
    protected $_myProtectedProperty; // observa guión bajo por no ser public

    // constructor 
    function __construct(){
    }

    public function hacerAlgoConMiClase($parametroRecibido){
        for ($i = 0; $i < self::LIMIT_OF_ITERATIONS; $i++){
            // lo que sea
        }
    }

    public function getMyProtectedProperty(){
        return $this->_myProtectedProperty;
    }
}
8. Emplea un Entorno de Desarrollo Integrado (IDE)
Un IDE es un editor de código que ofrece la posibilidad de depurar, autocompletar e identar el código. Existen multitud de alternativas, gratuitas y de pago. Entre las opciones gratuitas destacan Eclipse y Netbeans; por su parte, Zend Studio y PHP Designer destacan como opciones de pago.
9. Separa y reutiliza tu código
Evita tener archivos con cientos o miles de líneas. Agrupa las funciones que vayas a emplear con frecuencia en archivos e inclúyelos para su posterior reutilización. Ejemplo:

<?php 
class Ipl_Util_Date{
    ...
    public static function timestampToSpanishFormat($date, $dateSeparator, 
		$timeSeparator = ' a las '){
        if ($date == '') return null;
        $temp = explode(' ', $date);
        if (sizeof($temp) != 2) return null;
        $dates = explode('-', $temp[0]);
        return $dates[2] . $dateSeparator . $dates[1] 
		. $dateSeparator . $dates[0] 
		. $timeSeparator . $temp[1];
    }
}

Así, si alguna vez queremos convertir una fecha en formato timestamp a un formato con el que estamos más familiarizados, sólo tenemos que hacer <?php echo Ipl_Util_Date::timestampToSpanishFormat($myDate, '/') ?>.

10. Al iterar arrays, fija el valor máximo fuera del bucle
Cada llamada al método count() aumenta hasta en un 50% el tiempo de ejecución, según el tamaño del array.

// mal
for ($i = 0, $i < count($miArray); $i++){
   ... 
}
// bien
$limite = count($miArray);
for ($i = 0; $i < $limite; $i++){
    ...
}
11. Emplea el buffer de salida
En lugar de utilizar echo 'texto que sea', utiliza ob_start() para empezar a almacenar el texto en el búffer de salida. Para terminar la captura, puedes emplear ob_get_contents() y ob_get_clean(), o ob_end_clean().
12. Mantén las opciones de configuración en un archivo
A medida que tu aplicación vaya creciendo necesitarás acceder en distintos lugares a determinados valores. Almacenándolos todos en un único lugar, evitarás tener que modificar todos los archivos cada vez que haya un cambio. Imagina que programas un carrito de la compra y en un determinado momento hay que cambiar el IVA.
13. Incluyendo código
include, require y sus derivados (include_once, require_once) son sentencias, no métodos. No debe ponerse la ruta al fichero entre paréntesis.
Emplea siempre include o require en vez de include_once o require_once para que el cacheado de código sea más efectivo.
14. Codificación de caracteres
Emplea UTF-8 (sin BOM) en lugar de ANSI. Lo que en ANSI u otra codificación
puede ser un determinado caracter (una eñe, por ejemplo), en otra codificación puede ser algo completamente distinto. Si tu público emplea tu misma codificación no hay problema pero, si en un momento dado alguien de, por ejemplo, Rusia entra en tu página, verá la pantalla llena de caracteres sin sentido.
Si tu web va a estar disponible en más de un idioma, es indispensable que tu codificación sea UTF-8 (incluyendo la codificación y colación de la base de datos).
15. Minimiza el número de variables globales
Operar con variables globales es en torno a un 200% más costoso que hacerlo con locales.
16. Directiva AllowOverride
Si tu servidor web es Apache, emplea la directiva AllowOverride None donde sea posible.
Imagina una estructura de directorios como la siguiente: media/images/2013/03/my_image.jpg. Si AllowOverride está en All, antes de que Apache pueda servir el recurso my_image.jpg, debe recorrer todos los directorios desde la raíz hasta "/03" en búsqueda los archivos .htaccess por si en alguno de ellos se especificase alguna directiva sobre el objeto de la petición.
17. No implementes todas las estructuras de datos como objetos
Los array son más rápidos y consumen menos memoria que instanciar un objeto.
18. Incrementar o Decrementar variables: ++$i vs $i++
Pre-incrementar (++$i) es en torno a un 10% más rápido que post-incrementar ($i++). La razón es que cuando hacemos post-incremento, PHP necesita crear una variable temporal en la que almacenar el valor a ser incrementado.
19. Minimiza el número de consultas a la base de datos
Realizar una consulta es costosa en términos temporales. En todas aquellas ocasiones en que los datos no vayan a cambiar con mucha frecuencia, es interesante realizar una única vez la consulta y almacenar el resultado de ésta en un archivo de texto plano. Cuando se produzcan cambios en la consulta, se vuelve a generar el archivo a ser incluido.Por ejemplo: imagina que tienes una web de películas, y en algún sitio de la página se ve el listado de películas mejor valoradas. Para obtener las diez películas mejor valoradas tendrías que hacer una consulta similar a la siguiente:

$sqlVotos = 'SELECT p.id, p.titulo, SUM(v.voto) AS suma_votos, 
	COUNT(v.id) AS numero_votos, 
	(SUM(v.voto)/COUNT(v.id)) AS valoracion 
	FROM peliculas p 
INNER JOIN votos v ON p.id=v.id 
GROUP BY v.id_pelicula
ORDER BY valoracion DESC 
LIMIT 0,10';
$resVotos = mysql_query($sql);
$votos = mysql_fetch_array($res, MYSQL_ASSOC);

echo "<h3>Mejor valoradas</h3>n<ul class="list">";
foreach ($votos as $voto){
    echo '<li><a href="....">' . $voto['titulo'] 
	. ' (' . $voto['valoracion'] . ')</a></li>' . "n";
}
echo '</ul>';

Este script debería ejecutarse para todas y cada una de las peticiones de página que tuviera tu web. Lo que podemos hacer es ejecutar el siguiente código cada vez que se produzca una votación, o bien un Cron que se ejecute cada 30 minutos o el intervalo que consideremos:

$filename = PATH_TO_VOTACIONES_FILE . 'votos.txt';  // ruta al fichero
$handle = fopen($filename, 'w+'); // abrimos el fichero
// ejecutamos la consulta anterior ($sqlVotos / $resVotos)
foreach ($votos as $voto){
    fwrite($handle, '<li><a href="...">'. $voto['titulo'] 
	. ' (' . $voto['valoracion'] . ')</a></li>' . "n";
}
fclose($handle);

Entonces, sólo tendríamos que hacer un require PATH_TO_VOTACIONES_FILE . 'votos.txt'; para mostrar los votos.

20. isset()
La función isset() (isSet) resulta de una utilidad tremenda. Nos sirve tanto para saber si una determinada variable ha sido inicializada como para comprobar que un índice existe e incluso para trabajar con longitudes de cadenas de un modo más eficiente: si en un determinando momento necesitamos comprobar que una cadena tiene al menos una determinada longitud, por ejemplo que el nombre de usuario tenga más de 4 caracteres, lo más inmediato que se nos puede ocurrir es utilizar strlen()

if (strlen($username) < 5){
    ....
}

Pero, en tanto que strlen es una función, PHP necesita realizar un trabajo previo para ejecutar la llamada (convertirla a lowercase y buscarla en la tabla hash de funciones), además de ejecutar la propia función.

Por contra, isset no es una función sino una construcción del lenguaje. Esto significa que PHP no tendrá que hacer ninguna operación previa ni habrá sobrecarga.

Así, si queremos comprobar que una variable tiene más de una determinada longitud, podemos hacerlo de un modo más efectivo de la siguiente manera:

if (isset($username{5})){
    ....
}


Imagen | Freepik

7 votos, promedio: 5,00 de 57 votos, promedio: 5,00 de 57 votos, promedio: 5,00 de 57 votos, promedio: 5,00 de 57 votos, promedio: 5,00 de 5 (7 votos, media: 5,00 de 5)

Revisado por
Ingeniero informático por la Universidad UPV, programador y técnico de sistemas.