Lección 22 de 75 10 min de lectura

Valores de Retorno

El valor de retorno es lo que una función devuelve al código que la llamó. Dominar los tipos de retorno te permite escribir funciones predecibles y aprovechar las verificaciones de tipo de PHP moderno.

La sentencia return

return termina la ejecución de la función y devuelve un valor al código que la llamó:

PHP
<?php

declare(strict_types=1);

function sumar(int $a, int $b): int
{
    return $a + $b;  // Devuelve el resultado y termina
}

$resultado = sumar(5, 3);
echo $resultado; // 8

// return termina la función inmediatamente
function verificarEdad(int $edad): string
{
    if ($edad < 0) {
        return 'Edad inválida';  // Termina aquí si es negativo
    }

    if ($edad >= 18) {
        return 'Mayor de edad';  // Termina aquí si >= 18
    }

    return 'Menor de edad';  // Caso restante
}

echo verificarEdad(25);  // Mayor de edad
echo verificarEdad(-5);  // Edad inválida
echo verificarEdad(15);  // Menor de edad

Tipo de retorno void

Usa void cuando la función no devuelve ningún valor. Esto hace explícito que la función solo ejecuta acciones sin retornar datos:

PHP
<?php

declare(strict_types=1);

function mostrarMensaje(string $mensaje): void
{
    echo $mensaje . "\n";
    // No hay return, o return sin valor
}

function procesarDatos(array $datos): void
{
    foreach ($datos as $dato) {
        echo "Procesando: $dato\n";
    }
    return;  // return vacío es válido con void
}

// Esto causaría un error:
// function invalida(): void
// {
//     return 'algo';  // Error: función void no puede retornar valor
// }

mostrarMensaje('Hola');
$resultado = mostrarMensaje('Test');  // $resultado será null

Tipos de retorno nullable

Usa ?tipo para indicar que una función puede retornar el tipo especificado o null:

PHP
<?php

declare(strict_types=1);

// Puede retornar array o null
function buscarUsuario(int $id): ?array
{
    $usuarios = [
        1 => ['nombre' => 'Ana', 'email' => 'ana@example.com'],
        2 => ['nombre' => 'Luis', 'email' => 'luis@example.com'],
    ];

    return $usuarios[$id] ?? null;
}

$usuario = buscarUsuario(1);
if ($usuario !== null) {
    echo $usuario['nombre']; // Ana
}

$noExiste = buscarUsuario(99);
if ($noExiste === null) {
    echo 'Usuario no encontrado';
}

// Puede retornar string o null
function obtenerConfig(string $clave): ?string
{
    $config = [
        'app_name' => 'MiApp',
        'version' => '1.0.0',
    ];

    return $config[$clave] ?? null;
}

$nombre = obtenerConfig('app_name') ?? 'Aplicación';
echo $nombre; // MiApp

Union types en retorno (PHP 8+)

Los union types permiten que una función retorne uno de varios tipos posibles:

PHP
<?php

declare(strict_types=1);

// Retorna int o float dependiendo de la operación
function dividir(int $a, int $b): int|float
{
    if ($b === 0) {
        return 0;
    }

    $resultado = $a / $b;

    // Retorna int si es división exacta
    if ($resultado === floor($resultado)) {
        return (int) $resultado;
    }

    return $resultado;
}

echo dividir(10, 2);  // 5 (int)
echo dividir(10, 3);  // 3.3333... (float)

// Retorna valor o false (patrón común en PHP)
function buscarEnTexto(string $texto, string $buscar): int|false
{
    $posicion = strpos($texto, $buscar);
    return $posicion;  // int si encuentra, false si no
}

$resultado = buscarEnTexto('Hola mundo', 'mundo');
if ($resultado !== false) {
    echo "Encontrado en posición: $resultado"; // 5
}

// Múltiples tipos de retorno
function procesarValor(mixed $valor): string|int|array
{
    if (is_array($valor)) {
        return $valor;
    }

    if (is_numeric($valor)) {
        return (int) $valor;
    }

    return (string) $valor;
}

El tipo mixed

mixed (PHP 8+) indica que la función puede retornar cualquier tipo:

PHP
<?php

declare(strict_types=1);

// mixed = cualquier tipo (incluyendo null)
function obtenerValor(string $clave): mixed
{
    $datos = [
        'nombre' => 'Ana',
        'edad' => 25,
        'activo' => true,
        'tags' => ['php', 'web'],
    ];

    return $datos[$clave] ?? null;
}

$nombre = obtenerValor('nombre'); // string
$edad = obtenerValor('edad');     // int
$tags = obtenerValor('tags');     // array

// Úsalo cuando realmente necesites flexibilidad total
// Prefiere tipos específicos cuando sea posible
Prefiere tipos específicos

Usa mixed solo cuando sea necesario. Los tipos específicos proporcionan mejor documentación y detección de errores.

Retornar múltiples valores

PHP no permite retornar múltiples valores directamente, pero puedes usar arrays y destructuring:

PHP
<?php

declare(strict_types=1);

// Opción 1: Array asociativo (más legible)
function calcularEstadisticas(array $numeros): array
{
    $cantidad = count($numeros);
    $suma = array_sum($numeros);

    return [
        'min' => min($numeros),
        'max' => max($numeros),
        'suma' => $suma,
        'promedio' => $cantidad > 0 ? $suma / $cantidad : 0,
        'cantidad' => $cantidad,
    ];
}

$stats = calcularEstadisticas([1, 2, 3, 4, 5]);
echo $stats['promedio']; // 3
echo $stats['max'];      // 5

// Opción 2: Array indexado con destructuring
function dividirConResto(int $dividendo, int $divisor): array
{
    return [
        intdiv($dividendo, $divisor),
        $dividendo % $divisor,
    ];
}

[$cociente, $resto] = dividirConResto(17, 5);
echo "17 / 5 = $cociente resto $resto"; // 17 / 5 = 3 resto 2

// Opción 3: Array con claves para destructuring
function obtenerCoordenadas(string $ciudad): array
{
    $ubicaciones = [
        'Madrid' => ['lat' => 40.4168, 'lon' => -3.7038],
        'Barcelona' => ['lat' => 41.3851, 'lon' => 2.1734],
    ];

    return $ubicaciones[$ciudad] ?? ['lat' => 0.0, 'lon' => 0.0];
}

$coords = obtenerCoordenadas('Madrid');
echo "Latitud: {$coords['lat']}"; // Latitud: 40.4168

Early return (retorno temprano)

El patrón "early return" mejora la legibilidad al manejar casos especiales primero:

PHP
<?php

declare(strict_types=1);

// ❌ Sin early return (difícil de leer)
function calcularDescuento(float $total, ?string $cupon): float
{
    $descuento = 0.0;

    if ($total > 0) {
        if ($cupon !== null) {
            if ($cupon === 'VERANO20') {
                $descuento = $total * 0.20;
            } elseif ($cupon === 'NUEVO10') {
                $descuento = $total * 0.10;
            }
        }
    }

    return $descuento;
}

// ✅ Con early return (más claro)
function calcularDescuentoMejor(float $total, ?string $cupon): float
{
    if ($total <= 0) {
        return 0.0;
    }

    if ($cupon === null) {
        return 0.0;
    }

    return match ($cupon) {
        'VERANO20' => $total * 0.20,
        'NUEVO10' => $total * 0.10,
        default => 0.0,
    };
}

Ejemplo práctico

PHP
<?php

declare(strict_types=1);

// Sistema de validación con diferentes tipos de retorno

function validarEmail(string $email): array
{
    $errores = [];

    if (empty($email)) {
        $errores[] = 'El email es obligatorio';
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errores[] = 'El formato del email no es válido';
    }

    return [
        'valido' => count($errores) === 0,
        'errores' => $errores,
    ];
}

function validarPassword(string $password): array
{
    $errores = [];

    if (strlen($password) < 8) {
        $errores[] = 'La contraseña debe tener al menos 8 caracteres';
    }

    if (!preg_match('/[A-Z]/', $password)) {
        $errores[] = 'Debe contener al menos una mayúscula';
    }

    if (!preg_match('/[0-9]/', $password)) {
        $errores[] = 'Debe contener al menos un número';
    }

    return [
        'valido' => count($errores) === 0,
        'errores' => $errores,
    ];
}

function registrarUsuario(string $email, string $password, string $nombre): array
{
    $errores = [];

    // Validar email
    $resultadoEmail = validarEmail($email);
    if (!$resultadoEmail['valido']) {
        $errores = [...$errores, ...$resultadoEmail['errores']];
    }

    // Validar password
    $resultadoPassword = validarPassword($password);
    if (!$resultadoPassword['valido']) {
        $errores = [...$errores, ...$resultadoPassword['errores']];
    }

    // Validar nombre
    if (strlen($nombre) < 2) {
        $errores[] = 'El nombre debe tener al menos 2 caracteres';
    }

    // Si hay errores, retornar sin crear usuario
    if (count($errores) > 0) {
        return [
            'exito' => false,
            'usuario' => null,
            'errores' => $errores,
        ];
    }

    // Crear usuario (simulado)
    $usuario = [
        'id' => random_int(1000, 9999),
        'email' => $email,
        'nombre' => $nombre,
        'creado' => date('Y-m-d H:i:s'),
    ];

    return [
        'exito' => true,
        'usuario' => $usuario,
        'errores' => [],
    ];
}

// Uso
$resultado = registrarUsuario('ana@example.com', 'MiPassword123', 'Ana');

if ($resultado['exito']) {
    echo "Usuario creado: {$resultado['usuario']['nombre']}\n";
} else {
    echo "Errores:\n";
    foreach ($resultado['errores'] as $error) {
        echo "- $error\n";
    }
}

Ejercicios

Ejercicio 1: Funcion con retorno nullable

Crea una funcion buscarPorId que reciba un array de productos y un id (int). Debe retornar el producto si existe, o null si no se encuentra. Cada producto es un array con claves 'id' y 'nombre'.

Ver solucion
PHP
<?php
declare(strict_types=1);

function buscarPorId(array $productos, int $id): ?array
{
    foreach ($productos as $producto) {
        if ($producto['id'] === $id) {
            return $producto;
        }
    }

    return null;
}

$productos = [
    ['id' => 1, 'nombre' => 'Laptop'],
    ['id' => 2, 'nombre' => 'Mouse'],
    ['id' => 3, 'nombre' => 'Teclado'],
];

$encontrado = buscarPorId($productos, 2);
print_r($encontrado); // ['id' => 2, 'nombre' => 'Mouse']

$noExiste = buscarPorId($productos, 99);
var_dump($noExiste); // NULL

Ejercicio 2: Retornar multiples valores

Crea una funcion analizarTexto que reciba un string y retorne un array asociativo con: 'longitud' (int), 'palabras' (int) y 'mayusculas' (bool, true si todo esta en mayusculas).

Ver solucion
PHP
<?php
declare(strict_types=1);

function analizarTexto(string $texto): array
{
    return [
        'longitud' => strlen($texto),
        'palabras' => str_word_count($texto),
        'mayusculas' => $texto === strtoupper($texto) && $texto !== '',
    ];
}

$resultado = analizarTexto('Hola mundo');
print_r($resultado);
// ['longitud' => 10, 'palabras' => 2, 'mayusculas' => false]

$resultado2 = analizarTexto('ALERTA');
print_r($resultado2);
// ['longitud' => 6, 'palabras' => 1, 'mayusculas' => true]

Ejercicio 3: Early return

Crea una funcion categorizarEdad que reciba una edad (int) y retorne una categoria: 'nino' (0-12), 'adolescente' (13-17), 'adulto' (18-64), 'senior' (65+). Si la edad es negativa, retorna 'invalido'. Usa early return.

Ver solucion
PHP
<?php
declare(strict_types=1);

function categorizarEdad(int $edad): string
{
    if ($edad < 0) {
        return 'invalido';
    }

    if ($edad <= 12) {
        return 'nino';
    }

    if ($edad <= 17) {
        return 'adolescente';
    }

    if ($edad <= 64) {
        return 'adulto';
    }

    return 'senior';
}

echo categorizarEdad(-5);  // invalido
echo categorizarEdad(8);   // nino
echo categorizarEdad(15);  // adolescente
echo categorizarEdad(30);  // adulto
echo categorizarEdad(70);  // senior

¿Te está gustando el curso?

Tenemos cursos premium con proyectos reales y soporte personalizado.

Descubrir cursos premium