Hemos llegado al tercer artículo sobre las novedades de PHP 8, ahora ya conociendo el logo oficial de esta versión del lenguaje. Puedes consultar los otros dos artículos de esta serie en los enlaces a continuación:
¿Qué Hay de Nuevo en PHP 8 - Parte 1
¿Qué Hay de Nuevo en PHP 8 - Parte 2
En este artículo, hablaremos sobre otras 8 novedades de PHP 8. ¡Así que vamos allá!
Arguments Nombrados
Cuando trabajamos con funciones o métodos, siempre oímos hablar de argumentos o parámetros. Y sabemos que el orden en que informamos esos valores puede hacer toda la diferencia en el buen funcionamiento del código.
El lenguaje PHP siempre ha tenido argumentos referenciados a través de su posición. Pero con la versión 8, esto cambió. Ahora tenemos argumentos nombrados. Esto significa que podemos dejar claro a qué argumento se refieren los valores. Veamos un ejemplo de eso.
Creemos una función que retornará un array de los datos informados:
function create_user($username = "admin", $password = "admin", $is_admin = true) {
$data = [
'username' => $username,
'password' => $password,
'admin' => $is_admin
];
return $data;
}
Nota que esta función tiene un valor por defecto para todos los argumentos. Imagina que deseamos realizar la llamada de esta función, pero informando solo el argumento $password. Para hacer esto, solo hay que informar a la función el nombre del argumento sin el signo de $, definir un signo de : (dos puntos) y luego informar su valor:
print_r(create_user(password: '123456'));
Este código definirá el siguiente resultado:
Observa que la información de contraseña fue identificada correctamente, pero los otros dos parámetros recibieron sus valores predeterminados. Mediante los argumentos nombrados también podemos informar los argumentos en el orden que deseemos; ya no necesitamos estar atados al orden definido en la función. Por ejemplo, si deseamos informar el tercer argumento y luego el primero, no hay problema:
print_r(create_user(is_admin: 0, username: 'support'));
El resultado de este código será el siguiente:
Los datos también son reconocidos. Impresionante, ¿verdad?
Este mismo patrón puede ser utilizado en funciones nativas de PHP. Podemos ver un ejemplo de esto con la función array_fill(), que se usa para crear un array personalizado con los valores que determinamos. Espera tres parámetros: 1) start_index, que representa el índice inicial de nuestro array; 2) count, que representa la cantidad de elementos que tendrá el array; y 3) value, que es el valor de los elementos. Si deseamos usar los argumentos nombrados con esta función, podemos usar el siguiente código:
print_r(array_fill(value: 'Hcode', start_index: 0, count: 10));
El resultado será el siguiente:
Nuestro array fue creado con éxito ?.
Match Expression
La declaración switch() es una de las estructuras de control de flujo más utilizadas en cualquier lenguaje de programación, y en PHP no es diferente. En la versión 8 de PHP tendremos un nuevo recurso que promete simplificar esta estructura, la expresión match(). La estructura de la misma recuerda al switch(), pero un poco más simple. Veamos un ejemplo para comparar sus sintaxis.
Imagina que deseamos crear un control de flujo que pueda identificar el nivel de conocimiento o carrera de un programador, clasificándolo como “Júnior”, “Pleno” o “Sênior” basándose en un identificador. Podríamos hacer esto con el siguiente código:
$level_number = 3;
switch ($level_number) {
case 1:
$level = 'Sênior';
break;
case 2:
$level = 'Pleno';
break;
case 3:
$level = 'Júnior';
break;
}
echo $level;
El resultado sería el siguiente:
Vemos que el código funcionó correctamente. Podríamos escribir el mismo código usando la expresión match de esta forma:
echo match($level_number) {
1 => 'Sênior',
2 => 'Pleno',
3 => 'Júnior'
};
El resultado sería el mismo, pero nota que escribimos mucho menos esta vez. Hicimos la llamada al constructor echo directamente con el match(), algo que no es posible con el switch(). Además, no fue necesario preocuparnos por los varios breaks que son necesarios en el switch() para garantizar que no habrá un resultado no deseado.
La expresión match() tiene otro recurso que puede considerarse como una buena ventaja. La declaración switch() realiza la verificación solo de los valores que estamos comparando. La expresión match() realiza la verificación de valor y también del tipo de las variables. Esto garantiza que el control de flujo será aún más preciso. Veamos un ejemplo de esta cuestión.
Imagina que queremos realizar la verificación del valor del número 0. Vamos a compararlo tanto con su valor exacto como también con la cadena de este número. Haremos esto primeramente con el switch(), mediante este código:
switch (0) {
case '0':
$result = "Esta es la cadena cero";
break;
case 0:
$result = "Este es el número cero";
break;
}
echo $result;
En tu opinión, ¿cuál será el valor retornado? ¿Conseguirá entender que estamos buscando el número cero de hecho? Cuando accedemos al navegador, vemos el siguiente resultado:
El switch() identificó la cadena del número cero como el valor buscado, ya que solo verifica el valor. Ahora ejecutaremos el mismo código usando la expresión match():
echo match (0) {
'0' => 'Esta es la cadena cero',
0 => 'Este es el número cero'
};
Cuando accedemos al navegador, el valor retornado ahora es el siguiente:
Excelente, ahora sí identificamos el número cero de hecho, ya que el match() verifica tanto el valor como también el tipo del valor a ser comparado.
Una otra característica de la expresión match es que permite definir más de un caso para los valores comparados, algo que ya conocemos del switch(). Imagina por ejemplo que deseamos comprobar cuál es el nivel de acceso de un usuario basándonos en un número. Podríamos hacer esto con el siguiente código:
$level_access = 2;
echo match($level_access) {
1, 2 => 'Acceso Administrativo',
3, 4 => 'Acceso Público'
};
Nota que en esta situación definimos que tanto el valor 1 como el 2 puede representar el “Acceso Administrativo”. Así, al acceder al navegador, el resultado retornado será el siguiente:
¡El código funcionó correctamente! Y por último, podemos hablar de la cuestión del caso predeterminado, o default. También está presente en la expresión match(), y puede definirse de la siguiente forma:
echo match($level_access) {
1, 2 => 'Acceso Administrativo',
3, 4 => 'Acceso Público',
default => 'Acceso Público'
};
Ahora, si definimos que el acceso es 0 por ejemplo, el código no se romperá, el resultado será el siguiente:
Algo interesante que podemos notar en relación al default del match() es que, a diferencia del switch(), no es posible definirlo junto con otros valores. Es decir, el código a continuación no funcionaría:
echo match($level_access) {
1, 2 => 'Acceso Administrativo',
3, 4, default => 'Acceso Público' // Esta parte retornaría un error
};
¿Ya has podido pensar en situaciones en las que podrás utilizar este nuevo recurso de PHP? Todas las cuestiones que hablamos arriba nos ayudan a saber cuándo podemos usar la expresión match para simplificar nuestro código. Esta es sin duda una novedad muy interesante, ¿no es así?
Atributos Nativos en PHP
Usar atributos es una costumbre que puede ayudarnos a dejar nuestro código bien explicado. Esto también puede ayudarnos cuando necesitamos crear algún tipo de documentación de nuestros sistemas. PHP no tenía ninguna herramienta nativa que permitiera desarrollar estas anotaciones. Por eso, es muy común usar herramientas de terceros, como PHPDoc. Usando este generador de documentación, podríamos documentar un método usando la sintaxis a continuación:
class Clients {
/**
* @Route("/clients", methods={"POST"})
*/
public function create($data) {}
}
Pero, a partir de la versión 8, PHP tendrá anotaciones de atributos de manera nativa. Así, podríamos definir las mismas anotaciones del PHPDoc usando el código a continuación:
class Clients {
#[Route("/clients", methods: ["POST"])]
public function create($data) {}
}
Si tienes algún amigo que suele usar PHPDoc y que le gustará esta novedad de PHP 8, no dejes de compartir este artículo con él ?.
Funciones str_starts_with() y str_ends_with()
PHP 8 también introducirá nuevas funciones a su acervo de recursos. Dos funciones muy interesantes son str_starts_with() y str_ends_with(). Como sus nombres indican, el objetivo de estas funciones es comprobar, respectivamente, si una cadena inicia y si termina con una letra o conjunto de letras. Veamos un ejemplo de cada una de ellas.
La función str_starts_with() espera dos parámetros: 1) una cadena y 2) el conjunto de caracteres que estamos buscando en su inicio. Imagina que estamos trabajando en un sistema de registro y necesitamos garantizar que ningún usuario podrá registrar un correo electrónico con el nombre “hcode”, ya que este será un identificador reservado para una cantidad específica de usuarios. Podríamos usar la nueva función str_starts_with() para esto, usando el siguiente código:
$email = '[email protected]';
if (str_starts_with($email, 'hco')) {
echo 'Este es un correo electrónico reservado';
}
Así, si alguien desea registrar un correo electrónico que inicie con “hco”, verá el siguiente mensaje como retorno:
Antes necesitábamos definir la llamada de las funciones substr() y strpos() para realizar la misma verificación. Pero con el nuevo recurso de PHP 8 es mucho más simple, ¿no crees?
La función str_ends_with() también espera dos parámetros: 1) una cadena y 2) el conjunto de caracteres que estamos buscando en su final. Para hablar de esta, pensemos en la siguiente situación: imagina que deseamos crear una función que verifique si una palabra está en plural o en singular. Hablando de manera general, ¿cuál parámetro tenemos en cuenta para descubrir si una palabra está en plural? Las palabras en plural generalmente tendrán una “s” al final. Podríamos crear un if() ternario que verificaría esta condición usando la nueva función. El código sería así:
echo (str_ends_with($name, 's')) ? 'Esta palabra está en plural' : 'Esta palabra está en singular';
Así, si definimos la variable $name como “Computador”, veremos el siguiente resultado:
Pero, si definimos que tendrá el valor “Computadores”, el resultado será diferente:
Es claro que hay excepciones en esta regla respecto a saber si una palabra está en plural o en singular. Pero en este ejemplo pudimos notar que esta función puede identificar fácilmente los últimos caracteres de una cadena y podrá ayudarnos bastante en otras situaciones durante el desarrollo.
Función str_contains()
Otra función que llega con PHP 8 es la función str_contains(). Su objetivo es verificar si una cadena contiene una letra o palabra determinada en su estructura. Espera dos parámetros: 1) una cadena y 2) la palabra que estamos buscando en ella. Vamos a crear un ejemplo. Imagina que definimos una frase dentro de una variable:
$phrase = '¡El lenguaje PHP es sensacional!!!';
Queremos verificar si esta frase tiene la palabra “PHP”. Si es así, deseamos imprimir un mensaje en pantalla. Para esto, podríamos usar el siguiente if() ternario:
if (str_contains($phrase, 'PHP')) echo 'PHP fue encontrado';
Al acceder al navegador, veríamos el siguiente resultado:
Nota que la función pudo identificar la palabra en la frase y retornó un booleano true.
Esta nueva función tiene un pequeño detalle: si realizamos la búsqueda de una cadena vacía, siempre devolverá verdadero. Es decir, el siguiente código siempre sería true:
if (str_contains($phrase, '')) echo 'PHP fue encontrado';
Función fdiv()
Otra función es fdiv(). Se usa para realizar una división entre dos números y siempre retorna el resultado de la ecuación en notación de punto flotante. Esta función espera dos parámetros: 1) el dividendo y 2) el divisor de la ecuación. Veamos a continuación la llamada de esta función:
echo fdiv(450, 15);
Este código retorna el siguiente resultado en el navegador:
El resultado fue el esperado. Pero, como comentamos arriba, esta función retorna el valor como punto flotante o decimal. Así, si realizamos la división de dos decimales, el valor retornado será exacto. Veamos, por ejemplo, el siguiente código:
echo fdiv(4.5, 2.8);
Él retornará el siguiente resultado:
Vemos que el resultado decimal es correcto. Esto no ocurriría con otras funciones, como intdiv(), que arredondaría este resultado a 2.
Después de analizar estas características, quizás podamos pensar: “Esta función es bastante interesante. Sin embargo, ¿puedo hacer estas mismas operaciones usando el signo de barra (/)? ¿Qué diferencial puede ofrecerme esta función?”
En este momento, podemos analizar una particularidad de esta nueva función, que puede usarse para tratar uno de los errores más clásicos de la programación: intentar dividir un número por cero. Si intentamos hacer esto con PHP, se retornará un error, paralizando la ejecución del código. Sin embargo, si hacemos esta división usando la función fdiv(), obtendremos un resultado diferente. Veamos el siguiente código:
echo fdiv(450, 0);
Normalmente veríamos un error como retorno de su llamada, pero cuando accedemos al navegador, nos encontramos con este resultado:
Se nos retornó la cadena “INF”. Este retorno también puede ser las cadenas “-INF” (si realizamos la división con números negativos) o “NAN” (si dividimos el número 0 por 0). Este concepto se asemeja mucho a lo que vemos en JavaScript, que nativamente retorna la cadena “Infinity” cuando intentamos dividir un número por cero. Es posible obtener un resultado similar ahora con PHP 8, pero solo si usamos la función fdiv(). El error de división por cero sigue siendo el mismo si realizamos esta operación sin la función.
Función get_debug_type()
La próxima función que veremos es get_debug_type(). Podemos decir que es una alternativa a la función gettype(), ampliamente utilizada para identificar el tipo de dato de una variable. Esta nueva función tiene el objetivo de retornar los tipos de datos de una manera que estamos más acostumbrados a ver en otros lenguajes de programación o incluso en documentaciones. Veamos algunos ejemplos de esto.
Imagina que queremos verificar el tipo de dato de una variable que contiene un número entero. Realizaremos la llamada de las dos funciones en nuestro código:
$year = 2020;
var_dump(gettype($year)); // Manera convencional
echo "<br/>";
var_dump(get_debug_type($year)); // Manera nueva
Al acceder al navegador, vemos el siguiente resultado:
Nota que la función gettype() nos retornó “integer”. En contrapartida, la nueva función get_debug_type() nos retorna “int”, un identificador al que estamos más acostumbrados.
Otro ejemplo es en la cuestión de los números decimales. Veamos cómo estas funciones tratan este tipo de dato mediante el código a continuación:
$price = 999.90;
var_dump(gettype($price));
echo "<br/>";
var_dump(get_debug_type($price));
Al acceder al navegador, vemos el siguiente resultado:
Vemos que la función gettype() nos retornó “double”. Podemos entender este tipo de dato, pero puede que estemos más acostumbrados con el tipo de dato “float”. Si este es nuestro caso, podemos usar la función get_debug_type().
Veamos a continuación cómo estas funciones tratan un valor booleano:
$is_admin = true;
var_dump(gettype($is_admin));
echo "<br/>";
var_dump(get_debug_type($is_admin));
Este es el resultado que vemos al acceder al navegador:
En este ejemplo vemos que la función get_debug_type() nos retorna el valor “bool”, que también es muy común.
Hasta ahora, los ejemplos que hemos visto han variado de manera sutil los tipos de datos que se retornan. Sin embargo, cuando vemos la manera en que estas funciones miran a los objetos, podemos notar una gran diferencia. Veamos esta diferencia creando una clase llamada “Product” y verificando el tipo de dato de la variable que contendrá la nueva instancia de la misma:
class Product { }
$notebook = new Product();
var_dump(gettype($notebook));
echo "<br/>";
var_dump(get_debug_type($notebook));
Cuando accedemos al navegador, vemos el siguiente resultado:
Nota que la función gettype() retornó solo “object” como el tipo de la variable, de una manera algo genérica. Sin embargo, la función get_debug_type() retornó el nombre de la clase que esa objeto instanció, en este caso, “Product”. Muy interesante, ¿verdad? Esta nueva función realmente trajo recursos muy interesantes para PHP y puede ser que durante el desarrollo nos encontremos en situaciones en las que podremos usar estas dos funciones juntas.
Función get_resource_id()
La función get_resource_id() es otra función que llega como novedad en la versión 8 de PHP. Viene con el objetivo específico de ayudarnos a identificar el ID de un recurso (resource) definido en nuestro código. Por ejemplo, imagina que creamos una nueva variable del tipo resource al realizar la lectura de un archivo:
$file = fopen('./users.xml', "r");
Este recurso posee un ID dentro de nuestra página. Antiguamente, para identificar este ID, necesitábamos convertir la variable del recurso a un entero:
var_dump((int)$file);
Este código retornaría el ID del recurso, que podría ser cualquier número:
Ahora, si queremos identificar esta información, podemos usar esta nueva función:
var_dump(get_resource_id($file));
El resultado será el mismo:
Conclusión
En este artículo aprendimos más 8 novedades de PHP 8. Ahora estamos a la expectativa de ver las increíbles aplicaciones que podremos desarrollar con esta nueva versión de PHP. Si te gustó el contenido de este artículo, por favor compártelo con otras personas. Esto nos ayuda a continuar produciendo contenido sobre programación aquí en nuestro Blog.
Hasta el próximo artículo :)