Leccion 40 de 75 7 min de lectura

Union Types

Los Union Types permiten declarar que un parametro, propiedad o retorno puede ser de varios tipos, usando la sintaxis tipo1|tipo2.

Sintaxis basica

Usa el caracter | para separar los tipos permitidos:

PHP
<?php

declare(strict_types=1);

// Parametro que acepta int o float
function calcularDescuento(int|float $precio, int $porcentaje): float
{
    return $precio * (1 - $porcentaje / 100);
}

echo calcularDescuento(100, 20);    // 80
echo calcularDescuento(99.99, 10);  // 89.991

// Retorno que puede ser string o false
function buscarUsuario(int $id): string|false
{
    $usuarios = [1 => 'Ana', 2 => 'Luis'];
    return $usuarios[$id] ?? false;
}

$resultado = buscarUsuario(1);  // 'Ana'
$resultado = buscarUsuario(99); // false

Tipos nullables

Puedes incluir null en un union type. Es equivalente a usar ?tipo pero mas explicito:

PHP
<?php

declare(strict_types=1);

class Usuario
{
    public function __construct(
        public string $nombre,
        public string|null $telefono = null  // Equivale a ?string
    ) {}
}

// Con mas de dos tipos, debes usar union
function procesar(string|int|null $valor): void
{
    if ($valor === null) {
        echo 'Sin valor';
    } elseif (is_string($valor)) {
        echo "Texto: $valor";
    } else {
        echo "Numero: $valor";
    }
}

procesar('hola');  // Texto: hola
procesar(42);      // Numero: 42
procesar(null);    // Sin valor

Union types en propiedades

PHP
<?php

declare(strict_types=1);

class Configuracion
{
    // La propiedad puede ser string, int, bool o array
    public string|int|bool|array $valor;

    public function __construct(string|int|bool|array $valor)
    {
        $this->valor = $valor;
    }
}

$config1 = new Configuracion('localhost');
$config2 = new Configuracion(8080);
$config3 = new Configuracion(true);
$config4 = new Configuracion(['host' => 'localhost', 'port' => 8080]);

El tipo false

PHP 8 permite usar false como tipo en unions, util para funciones que retornan false en caso de error:

PHP
<?php

declare(strict_types=1);

function encontrarIndice(array $items, mixed $buscar): int|false
{
    $indice = array_search($buscar, $items, true);
    return $indice; // int si encuentra, false si no
}

$colores = ['rojo', 'verde', 'azul'];

$resultado = encontrarIndice($colores, 'verde');
if ($resultado !== false) {
    echo "Encontrado en posicion: $resultado"; // 1
}

$resultado = encontrarIndice($colores, 'amarillo');
if ($resultado === false) {
    echo 'No encontrado';
}

Intersection types (PHP 8.1)

PHP 8.1 introduce intersection types con &, que requieren que el valor implemente TODOS los tipos:

PHP PHP 8.1+
<?php

declare(strict_types=1);

interface Serializable
{
    public function serializar(): string;
}

interface Validable
{
    public function esValido(): bool;
}

// El parametro debe implementar AMBAS interfaces
function guardar(Serializable&Validable $objeto): void
{
    if ($objeto->esValido()) {
        $datos = $objeto->serializar();
        echo "Guardando: $datos";
    }
}

class Documento implements Serializable, Validable
{
    public function __construct(private string $contenido) {}

    public function serializar(): string
    {
        return json_encode(['contenido' => $this->contenido]);
    }

    public function esValido(): bool
    {
        return strlen($this->contenido) > 0;
    }
}

guardar(new Documento('Hola mundo'));

Ejercicios

Ejercicio 1: Funcion formatear

Crea una funcion formatear que reciba int|float|string y retorne siempre un string formateado.

Ver solucion
PHP
<?php

declare(strict_types=1);

function formatear(int|float|string $valor): string
{
    if (is_int($valor)) {
        return "Entero: $valor";
    }
    if (is_float($valor)) {
        return 'Decimal: ' . number_format($valor, 2);
    }
    return "Texto: $valor";
}

echo formatear(42);       // Entero: 42
echo formatear(3.14159);  // Decimal: 3.14
echo formatear('hola');   // Texto: hola

Ejercicio 2: Clase Respuesta

Crea una clase Respuesta con una propiedad datos que pueda ser array|string|null y un metodo que indique si tiene datos.

Ver solucion
PHP
<?php

declare(strict_types=1);

class Respuesta
{
    public function __construct(
        public array|string|null $datos = null
    ) {}

    public function tieneDatos(): bool
    {
        if ($this->datos === null) {
            return false;
        }
        if (is_array($this->datos)) {
            return count($this->datos) > 0;
        }
        return strlen($this->datos) > 0;
    }
}

$r1 = new Respuesta(['id' => 1]);
$r2 = new Respuesta(null);
echo $r1->tieneDatos(); // true
echo $r2->tieneDatos(); // false

¿Te está gustando el curso?

Cursos premium con proyectos reales y soporte.

Descubrir cursos premium