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.
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.
- 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