Conocemos las condiciones en PHP, pero ¿qué tan eficientes son las que tu escribes? Las condiciones pueden afectar la legibilidad de tu código e incluso afectar el rendimiento de tu aplicación.

Los problemas en las condiciones

He visto a desarrolladores nuevos en grupos de Facebook publicar su código, ¿y saben qué es lo que he notado? Problemas en sus condiciones:

  • No son para nada legibles ni eficientes, por lo tanto, son complejas.
  • Ejecutan condiciones de más, provocando el famoso callback hell.
  • No utilizan las condiciones Yoda (Esto puede ser opcional en cada desarrollador, pero yo lo recomiendo como buena práctica).

Yo sufrí lo mismo; y es que cuando estás empezando a desarrollar en PHP, como que te cuesta encontrar una guía de buenas prácticas al momento de estar desarrollando.

Yo encontré la guía PHP: The Right Way muy tarde, se los recomiendo.

Nota: El código que verás en todo el post estará en inglés, ¿por qué? La respuesta te la cuento en este post sobre cómo debes nombrar tus variables apropiadamente.

Tu código debe ser legible, no lo hagas más complejo

Hay una verdad en los programadores:

Los programadores pasamos la mayor parte de nuestro tiempo leyendo código que escribiéndolo.

Por lo tanto, todo el código que nosotros escribamos, deberá ser legible para que tanto nosotros como otros programadores lo lean rápido y por ende, el código sea fácil de entender.

¿No queremos gastar nuestro tiempo tratando de adivinar lo que hace el código o si?

Lo siguiente pasa muy seguido en los desarrolladores nuevos:

<?php
 
$animals = array(
'dog',
'cat',
'elephant',
);
 
if( is_array( $animals ) ) {
if( ! empty( $animals ) ) {
do_something();
}
}

¿Si notas cómo el código de arriba se hace un poco difícil de leer? Entre más tedioso sea de leer, más complejo se volverá tu código.

El código anterior es un ejemplo de condiciones anidadas. Ahora, ¿Qué ocurre cuando empiezas a anidar condición tras condición, función tras función?

Ocurre el famoso callback hell; la siguiente imagen no contiene código PHP, pero es un ejemplo muy claro de un callback hell, condiciones tras condiciones (abre la imagen en una pestaña para verla mejor, si es que te atreves):

Condiciones anidadas provocando callback hell

¿Pudiste descifrar lo que hace el código? ¡Yo ni me tomé el tiempo de leerlo! Tan sólo mira esa complejidad. Eso es lo que tratamos de evitar.

La solución de nuestro código anterior sería usar los operadores lógicos, en este caso, el operador AND:

<?php
 
$animals = array(
'dog',
'cat',
'elephant',
);
 
if( is_array( $animals ) && ! empty( $animals ) ) {
do_something();
}

¿Notas la diferencia? Es más legible y menos complejo. Los operadores lógicos están aquí para ayudarnos, así que pon atención a tus clases de Matemáticas Discretas (bueno, al menos yo lo vi en esa materia).

Usa cláusulas de guardia

Éste método funciona como un guardia que protege tu código, para poder llegar a la siguiente sección del código debes pasar ese guardia, y así sucesivamente.

Gráficamente trabaja así:

Clausulas de Guardia

¿Pero realmente de qué sirve? Nos aporta mayor legibilidad a nuestro código, nos ayuda a no ejecutar código de más y evita el callback hell.

El siguiente ejemplo no tiene cláusulas de guardia:

<?php
 
function is_user_registered( $username ) {
$usernames_list = array(
'roelmagdaleno',
'rokumetal',
'elbuenprogramador117',
);
 
$user_data = array();
 
if( in_array( $username, $usernames_list ) ) {
$user_data = get_user_data( $username );
}
 
return $user_data;
}

La función anterior nos dice que si el usuario está registrado, nos retorne los datos del usuario que está tratando de iniciar sesión, en caso contrario, mandemos un array vacío.

Ahora, mira la misma función pero usando las cláusulas de guardia:

<?php
 
function is_user_registered( $username ) {
$usernames_list = array(
'roelmagdaleno',
'rokumetal',
'elbuenprogramador117',
);
 
$user_data = array();
 
if( ! in_array( $username, $usernames_list ) ) {
return $user_data;
}
 
return get_user_data( $username );
}

¿Ves como hemos negado la función in_array()? Le estamos diciendo que si el usuario no existe, retorna un array vacío, en cambio, si existe, continúa con el código y obtiene los datos del usuario.

¡Así es como funcionan las cláusulas de guardia! Tienes que pasar cada guardia para proseguir ejecutando el código.

Otro ejemplo, pero ahora con condiciones anidadas:

<?php
 
function is_current_user_admin( $username ) {
$usernames_list = array(
'roelmagdaleno',
'rokumetal',
'elbuenprogramador117',
);
 
if( in_array( $username, $usernames_list ) ) {
$user_data = get_user_data( $username );
 
if( 'administrator' === $user_data['role'] ) {
return true;
}
}
 
return false;
}

La función anterior valida si el usuario actual que está tratando de iniciar sesión es un administrador o no. Pero, ¿si sientes que pierdes un poco de tiempo tratando de leer el código?

Bien, entonces, la función anterior sería de la siguiente forma usando cláusulas de guardia:

<?php
 
function is_current_user_admin( $username ) {
$usernames_list = array(
'roelmagdaleno',
'rokumetal',
'elbuenprogramador117',
);
 
if( ! in_array( $username, $usernames_list ) ) {
return 'The user does not exists.';
}
 
$user_data = get_user_data( $username );
 
if( 'administrator' !== $user_data['role'] ) {
return false;
}
 
return true;
}

¡Estupendo! Eliminamos la condición anidada y ahora es más fácil de leer el código, y un extra fue que evitamos un posible callback hell.

¿Tienes funciones que contengan condiciones anidadas? Trata de convertirlas usando cláusulas de guardia y pega tus resultados en los comentarios.

Evita usar “else” en tus condiciones

¿Enserio, no usar el else? Sí, hablo enserio.

¿No te ha pasado que cuando usas la palabra reservada else, se te dificulta leer más el código? Exacto.

Esta declaración lo que hace es agregarle más complejidad a nuestro código y por ende, más difícil de leer. Por ejemplo, sé que puedes leer el siguiente código, pero ¿cuánto te tardas en entender lo que realmente hace?:

<?php
 
$username = $_POST['username'];
$password = $_POST['password'];
 
if( empty( $username ) || empty( $password ) ) {
return 'user-login.php';
} elseif( ! empty( $username ) && ! empty( $password ) && 'roelmagdaleno' === $verification_code ) {
$sql = 'My SQL Query';
// More code here...
} else {
echo 'Ups! Your verification code is wrong!';
}

Bueno, el código representa un inicio de sesión, pero volvemos a lo mismo: legibilidad y complejidad. Y todos hemos escrito código parecido al anterior, no me dejarán mentir.

¿Cómo podemos evitar el else? Aquí tenemos dos soluciones:

Usar funciones para validar los datos y cláusulas de guardia; por lo tanto, el código anterior quedaría de la siguiente manera:

<?php
 
$username = $_POST['username'];
$password = $_POST['password'];
 
if ( empty( $username ) || empty( $password ) ) {
return 'user-login.php';
}
 
if( ! validate_password_and_user_data( $username, $password, $verification_code ) ) {
return 'Something is wrong with your data.';
}
 
return 'All good! Go to dashboard.';
 
function validate_password_and_user_data( $username, $password, $verification_code ) {
if( 'roelmagdaleno' !== $verification_code ) {
return false;
}
 
$sql = 'My SQL query to get username data.';
 
if( $password !== $sql['password'] ) {
return false;
}
 
return true;
}

¿Es más código? Sí, pero ésta solución hace que nuestros ojos no sangren al momento de ver el código, y no, no hemos usado ni un else.

El operador ternario

Vamos a usar un código directo, ¿has escrito un código como el siguiente?

<?php
 
$new_color = '';
 
if( isset( $_POST['color'] ) ) {
$new_color = $_POST['color'];
} else {
$new_color = 'red';
}
 
echo 'The current color is ' . $new_color;

Lo que estamos haciendo en el código anterior es que si existe el valor de un color que es traído desde un formulario, lo asigne a la variable $new_color, pero, sino existe, asigna un color por default.

El operador ternario puede reducir este tipo de condiciones con la siguiente sintaxis:

condición ? valor_si_es_verdadero : valor_si_es_falso;

Siguiendo la sintaxis anterior, nuestro código ahora sería:

<?php
 
$new_color = isset( $_POST['color'] ) ? $_POST['color'] : 'red';
 
echo 'The current color is ' . $new_color;

¡Wow! Nos ahorramos 5 líneas de código.

Una buena práctica que siempre hago es hacer primero la condición sin el operador ternario, y después, ya que he analizado bien mi condición, aplico el operador ternario.

Si usas otro lenguaje de programación, busca en este enlace si es compatible, o puedes probar directo en tu código.

Operador de fusión de null

Y hay una característica mucho mejor, pero solo es a partir de PHP 7, y se llama: operador de fusión de null. Su sintaxis es:

variable_a_verificar_si_existe ?? valor_por_default;

Y nos sirve para verificar si una variable existe, y si existe y no es null, asigna ese valor a la variable, en caso contrario, asignará el valor por default. Por ejemplo:

<?php
 
$username = $_GET['username'] ?? 'John Doe';

Si $_GET['username'] existe y no es null, entonces la variable $username será igual a $_GET['username'], en caso contrario, será igual a John Doe.

Realmente, este operador hace una operación ternaria por detrás. El código anterior equivale a esta operación ternaria:

<?php
 
$username = isset( $_GET['username'] ) ? $_GET['username'] : 'John Doe';

Recuerda, sólo funciona a partir de PHP 7 para arriba.

Condiciones Yoda

No explicaré aquí lo que es una condición Yoda, ya que he escrito un post específico para ese tema, y lo puedes leer en éste enlace.

Aplica los conocimientos aprendidos

Me da mucho gusto que hayas llegado hasta aquí, y espero que hayas aprendido algo, pero si te ha quedado alguna duda, tienes algún comentario ó sientes que me faltó una buena práctica, me gustaría que la compartieras en la caja de comentarios.

También te invito a compartir esta guía de buenas prácticas para que más desarrolladores nuevos aprendan a desarrollar de manera legible y menos compleja.

Y doy el agradecimiento a Carl Alexander por hacer su post del cual me he inspirado para escribir este.

0

Escrito por Roel Magdaleno

Desarrollador Backend y Performance Engineer.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *