Exprimiendo los tipos de PHP7 🐘

En las últimas versiones de PHP se han introducido mejoras en cuanto al soporte de tipos. A pesar de que estamos conmocionados por ser el último día de la promoción 3x1 para CodelyTV Pro, en este vídeo veremos cómo sacarle provecho. Al final del post tienes las instrucciones para entrar en el sorteo de la entrada a la Polycon!

Tipos dinámicos

Un lenguaje es dinámicamente tipado cuando es él quien deduce el tipo de datos de las variables y no se lo tenemos que indicar nosotros. En el siguiente ejemplo vemos como PHP estaría deduciendo el tipo resultante de sumar un int y un string que contiene un entero:

var_dump(1 + "1"); // Output: int(2)

Al ser dinámicamente tipado, además de interpretado, PHP no tiene un proceso de compilación, si no que es en tiempo de ejecución cuando PHP valida si una determinada variable tiene un determinado método, o no. Esto se conoce como Duck Typing:

function greeting($from, $to)
{
    return $from->name() . " says hello to " . $to->name();
}

echo greeting("Rafa", "Javi"); // Output \*en run-time\*: Fatal error: Uncaught Error: Call to a member function name() on string

final class Person
{
    private $name;

    public function \_\_construct($name)
    {
        $this->name = $name;
    }

    public function name()
    {
        return $this->name;
    }
}

$rafa = new Person("Rafa");
$javi = new Person("Javi");

echo greeting($rafa, $javi); // Output: Rafa says hello to Javi

Dicho esto, vamos a hacer un repaso por la evolución de PHP al respecto de los tipos:

Type Declaration (antes llamado Type Hinting)

A partir de PHP 5.0 tenemos la posibilidad de especificar el tipo de datos que contiene una determinada variable al ser recibida como argumento. Esto aporta cierta robustez a los contratos de nuestros métodos y deja atrás la posibilidad del Duck Typing tal y como antes veíamos: A pesar de ser un avance, seguía teniendo sus limitaciones: Sólo se podían especificar clases o interfaces, en ningún caso tipos primitivos del lenguaje.

  • PHP 5.1 introdujo la posibilidad de especificar array como tipo de entrada
  • PHP 5.4 introdujo soporte a callable permitiendo asegurarnos que recibíamos una función de primer y mo valor
  • PHP 7.0 introdujo soporte a primitivos como bool, string, int, y float
  • PHP 7.1 introduce soporte a iterable entendiendo que esto acepta tanto implementaciones de Treaversable, como arrays primitivos

Con lo cuál, tenemos que podemos refactorizar la función anterior a algo como:

function greeting(Person $from, Person $to)
{
    return $from->name() . " says hello to " . $to->name();
}

echo greeting("Rafa", "Javi"); // Output \*en run-time\*: Fatal error: Uncaught TypeError: Argument 1 passed to greeting() must be an instance of Person, string given

$rafa = new Person("Rafa");
$javi = new Person("Javi");

echo greeting($rafa, $javi); // Output: Rafa says hello to Javi

Return Type

PHP 7.0 introduce la posibilidad de añadir tipos de retorno en nuestras funciones, haciendo que finalmente ganen la robustez que merecen. Ahora sí podemos declarar interfaces que expresen de forma explícita en el contrato toda la información necesaria para las implementaciones, y los clientes de estas interfaces tendrán toda la información necesaria:

function greeting(Person $from, Person $to): string
{
    return $from->name() . " says hello to " . $to->name();
}

Además, en PHP 7.1 se introduce la opción de especificar void como tipo de retorno. Con lo cuál, de esta manera podemos hacer explícito el hecho de que una determinada función no retorna ningún valor y, por lo tanto, esa función tiene el propósito de producir un side-effect como los ejemplos que comentamos en el vídeo. Aún a día de hoy debemos indicar las excepciones que pueden ser lanzadas por un método a través de documentación, mientras que en otros lenguajes se pueden especificar a modo de contrato también (annotations de Java).

Strict Types

Otra funcionalidad al respecto de tipos incorporada en PHP 7.0 es la sentencia declare(strict_types=1);. Esta sentencia evita castings automáticos que hace PHP en caso de no especificar esta sentencia:

<?php

function greeting(string $fromName, string $toName): string
{
    return $fromName . " says hello to " . $toName;
}

echo greeting("Rafa", 123); // Output: Rafa says hello to 123

Como vemos a continuación, si especificamos esta sentencia a pesar de que haya un casting disponible de int(123) a string("123"), PHP no lo realiza y lanza un Fatal error:

<?php

declare(strict\_types=1);

function greeting(string $fromName, string $toName): string
{
    return $fromName . " says hello to " . $toName;
}

echo greeting("Rafa", 123); // Output: Fatal error: Uncaught TypeError: Argument 2 passed to greeting() must be of the type string, integer given

Lo ideal al respecto de la declaración de tipos estricta hubiera sido poder declararla a nivel de proyecto. No obstante, dado que si definimos algo así en el php.ini, afectaría al código de nuestras dependencias, prefirieron ser conservadores y definirlo a nivel de proyecto. A pesar de esto, teniendo en cuenta la madurez de Composer en el ecosistema PHP, quizá se podría haber aprovechado para declararlo dentro del composer.json, o para no mezclar, en un archivo específico tipo strict_types.json, que permitiese definir reglas de exclusión en base a directorios. En cualquier caso, esto no es así. Con lo que os recomendamos que os modifiquéis la plantilla "New PHP Class" de vuestro IntelliJ/PhpStorm para que incluya por defecto esta declaración.

Nullable Type

PHP 7.1 introduce la posibilidad de especificar de forma explícita que un determinado tipo puede ser null. Esto va muy bien para los casos prácticos que comentamos en el vídeo, pero siguiendo con el ejemplo del post, permitiría cosas como:

<?php

declare(strict\_types=1);

function greeting(string $fromName, ?string $toName): ?string
{
    if (is\_null($toName)) {
        return null;
    }

    return $fromName . " says hello to " . $toName;
}

echo greeting("Rafa", "Javi"); // Output: Rafa says hello to Javi
echo greeting("Rafa", null); // Output: "" (vacío)
echo greeting(null, "Javi"); // Output: Fatal error: Uncaught TypeError: Argument 1 passed to greeting() must be of the type string, null given

Conclusión sobre tipos y PHP

Como hemos podido ver, la evolución del soporte a tipos de PHP desde la versión 5 hasta la 7.1 ha sido notable. A pesar de que esto no supone ninguna mejora con respecto a las funcionalidades disponibles en otros lenguajes, al menos actualiza y pone un poco al día el lenguaje para permitir un estilo de programación con el que, al menos nosotros, nos sentimos mucho más cómodos 🙂 Por último, recordarte que hoy es el último día para aprovechar la oferta del 3x1 para Codely TV Pro. La plataforma de cursos de CodelyTV 🤓

Sorteo entrada Polycon 2017 🎟️🎯🐘

Este 6 y 7 de Octubre tiene lugar en Barcelona la conferencia de ingeniería de Software Polycon. Es una conferencia agnóstica de lenguajes de programación que se celebra por primera vez este año y ya cuenta con ponentes internacionales de primer nivel. Se hablará desde Arquitectura Hexagonal hasta Event Sourcing pasando por Microservicios, novedades de Symfony 4, bases de datos en grafos como Neo4j, y mucho más. Si queréis más información aquí tenéis la web oficial de Polycon. Son muy buena gente y nos han cedido una entrada para que la sorteemos entre los seguidores de CodelyTV, así que simplemente tenéis que hacer 3 sencillos pasos para entrar en el sorteo:

Con esto entrarás en el sorteo de la entrada valorada en 84€ y el martes 19 de Septiembre anunciaremos el ganador. ¡Mucha suerte! 🙂

Paga según tus necesidades

lite (sólo mensual)

Cargando…
al mes
  • Acceso a un subconjunto de cursos para sentar las bases para un código mantenible, escalable y testable
  • Factura de empresa
Popular

standard

Cargando…
Ahorra 121
Pago anual de 0
al mes
  • Catálogo completo de cursos
  • Retos de diseño y arquitectura
  • Vídeos de soluciones destacadas de los retos
  • Recibir ofertas de empleo verificadas por Codely
  • Factura de empresa

premium

Cargando…
Ahorra 89
Pago anual de 0
al mes
  • Todo lo anterior
  • Más beneficios próximamente

No subiremos el precio mientras mantengas tu suscripción activa