Skip to content

Funciones ​

Las funciones te permiten empaquetar código con un nombre y reutilizarlo. En esta lección aprenderás a crear funciones con tipos, valores por defecto, parámetros con nombre, funciones variádicas, closures y funciones flecha: todo lo que necesitas para escribir PHP moderno y ordenado.

Concepto ​

Una función es como una receta: tiene un nombre ("hacer café"), ingredientes de entrada (los parámetros: agua, café) y un resultado (el valor de retorno: una taza de café). Una vez escrita, la usas las veces que quieras sin volver a explicar los pasos.

Beneficios:

  • No te repites (principio DRY: Don't Repeat Yourself).
  • Si hay un bug, lo corriges en un solo lugar.
  • El código se lee como una historia: calcularTotal(), enviarCorreo(), validarEmail().

Ejemplo básico ​

php
<?php
declare(strict_types=1);

// Definición
function saludar(string $nombre): string
{
    return "Hola, $nombre";
}

// Llamada
echo saludar('Marta'); // Hola, Marta

Anatomía:

  • function palabra clave.
  • saludar nombre (en camelCase, idealmente un verbo).
  • string $nombre parámetro con su tipo.
  • : string tipo de retorno.
  • return devuelve el valor y termina la función.

Tipado ​

PHP 8 permite tipar parámetros y retornos con mucha precisión:

php
<?php
declare(strict_types=1);

function calcularIva(float $monto, float $tasa = 0.16): float
{
    return round($monto * $tasa, 2);
}

// ?string = puede ser string o null (tipo "nullable")
function obtenerApodo(?string $apodo): string
{
    return $apodo ?? 'Sin apodo';
}

// Tipos unión: acepta int O float
function formatearPrecio(int|float $precio): string
{
    return '$' . number_format($precio, 2);
}

// void: la función no devuelve nada
function registrarLog(string $mensaje): void
{
    file_put_contents(__DIR__ . '/app.log', date('c') . " $mensaje\n", FILE_APPEND);
}

// never: la función nunca termina normalmente (redirige o lanza excepción)
function redirigir(string $url): never
{
    header("Location: $url");
    exit;
}

// mixed: cualquier tipo (úsalo poco)
function depurar(mixed $valor): void
{
    echo '<pre>' . print_r($valor, true) . '</pre>';
}

Tipos disponibles: int, float, string, bool, array, callable, iterable, object, mixed, void, never, null, true, false, nombres de clases y uniones (int|string).

Valores por defecto y parámetros con nombre ​

php
<?php
declare(strict_types=1);

function crearBoton(
    string $texto,
    string $color = 'azul',
    string $tamano = 'mediano',
    bool $deshabilitado = false
): string {
    $attr = $deshabilitado ? ' disabled' : '';
    return "<button class=\"btn btn-$color btn-$tamano\"$attr>$texto</button>";
}

echo crearBoton('Guardar');                         // usa todos los valores por defecto
echo crearBoton('Borrar', 'rojo');

// Parámetros con nombre (PHP 8): te saltas los que no te interesan
echo crearBoton('Enviar', deshabilitado: true);
echo crearBoton(texto: 'Ver más', tamano: 'chico');

Buena práctica

Los parámetros con valor por defecto van al final. Y cuando una función tiene muchos booleanos, llámala con parámetros con nombre: crearBoton('Enviar', deshabilitado: true) se entiende; crearBoton('Enviar', 'azul', 'mediano', true) no.

Funciones variádicas y spread ​

... recibe cualquier cantidad de argumentos como un array:

php
<?php
declare(strict_types=1);

function sumar(int|float ...$numeros): int|float
{
    return array_sum($numeros);
}

echo sumar(1, 2, 3);        // 6
echo sumar(10, 20, 30, 40); // 100

// Spread: "desempaqueta" un array como argumentos
$valores = [5, 5, 5];
echo sumar(...$valores);    // 15

Ámbito (scope) ​

Las variables dentro de una función no ven las de fuera, y viceversa.

php
<?php
$iva = 0.16;

function precioConIva(float $precio): float
{
    // echo $iva; // Warning: Undefined variable $iva
    return $precio * 1.16;
}

Existe la palabra global, pero evítala: hace el código difícil de seguir y de probar. Pasa los datos como parámetros o usa constantes.

php
<?php
const IVA = 0.16; // Las constantes sí son visibles en todas partes

function precioConIva(float $precio, float $tasa = IVA): float
{
    return $precio * (1 + $tasa);
}

Variables estáticas ​

Conservan su valor entre llamadas:

php
<?php
function siguienteId(): int
{
    static $id = 0; // Se inicializa sólo la primera vez
    return ++$id;
}

echo siguienteId(); // 1
echo siguienteId(); // 2
echo siguienteId(); // 3

Paso por valor y por referencia ​

php
<?php
function agregarIva(float $precio): float
{
    $precio *= 1.16; // Modifica la copia local
    return $precio;
}

function agregarIvaRef(float &$precio): void
{
    $precio *= 1.16; // Modifica la variable original
}

$p = 100;
agregarIva($p);
echo $p; // 100 (no cambió)

agregarIvaRef($p);
echo $p; // 116 (cambió)

Prefiere devolver valores en lugar de modificar por referencia: es más predecible.

Funciones anónimas (closures) ​

Funciones sin nombre que se guardan en variables o se pasan como argumentos.

php
<?php
$saludar = function (string $nombre): string {
    return "Hola, $nombre";
};

echo $saludar('Iván');

// Para usar variables de fuera, se capturan con use
$descuento = 0.2;
$aplicarDescuento = function (float $precio) use ($descuento): float {
    return $precio * (1 - $descuento);
};

echo $aplicarDescuento(500); // 400

Funciones flecha fn ​

Versión corta para funciones de una sola expresión. Capturan automáticamente las variables de fuera (por valor).

php
<?php
$descuento = 0.2;

$aplicarDescuento = fn(float $precio): float => $precio * (1 - $descuento);
echo $aplicarDescuento(500); // 400

// Brillan con funciones de arrays
$precios = [100, 250, 80];
$conIva = array_map(fn($p) => $p * 1.16, $precios);
$caros  = array_filter($precios, fn($p) => $p > 90);

print_r($conIva); // [116, 290, 92.8]
print_r($caros);  // [0 => 100, 1 => 250]

Callables y funciones de primera clase ​

php
<?php
// Pasar el nombre de una función como string
$nombres = ['ana', 'luis'];
print_r(array_map('ucfirst', $nombres)); // ['Ana', 'Luis']

// Sintaxis de primera clase (PHP 8.1): más segura que un string
$mayusculas = strtoupper(...);
echo $mayusculas('hola'); // HOLA

// Una función que recibe otra función
function aplicarATodos(array $items, callable $fn): array
{
    $resultado = [];
    foreach ($items as $item) {
        $resultado[] = $fn($item);
    }
    return $resultado;
}

print_r(aplicarATodos([1, 2, 3], fn($n) => $n ** 2)); // [1, 4, 9]

Ejemplo real: utilidades de un proyecto ​

Es habitual tener un archivo helpers.php con funciones reutilizables:

php
<?php
declare(strict_types=1);

/**
 * Escapa texto para mostrarlo en HTML de forma segura (evita XSS).
 */
function e(?string $texto): string
{
    return htmlspecialchars($texto ?? '', ENT_QUOTES, 'UTF-8');
}

/**
 * Formatea un monto como moneda mexicana.
 */
function dinero(int|float $monto, string $moneda = 'MXN'): string
{
    return '$' . number_format($monto, 2, '.', ',') . " $moneda";
}

/**
 * Convierte un título en un "slug" para URLs: "Hola Mundo!" → "hola-mundo"
 */
function slug(string $texto): string
{
    $texto = mb_strtolower($texto, 'UTF-8');
    // Quita acentos: á → a, ñ → n
    $texto = strtr($texto, ['á'=>'a','é'=>'e','í'=>'i','ó'=>'o','ú'=>'u','ü'=>'u','ñ'=>'n']);
    $texto = preg_replace('/[^a-z0-9]+/', '-', $texto); // Todo lo raro → guion
    return trim($texto, '-');
}

/**
 * Redirige y detiene el script.
 */
function redirigir(string $url): never
{
    header("Location: $url");
    exit;
}

echo e('<b>Hola</b>');            // &lt;b&gt;Hola&lt;/b&gt;
echo dinero(1234.5);              // $1,234.50 MXN
echo slug('¡Café con Leche y Ñandú!'); // cafe-con-leche-y-nandu

Error común

Declarar dos veces la misma función (por ejemplo, al hacer include del mismo archivo dos veces) produce Fatal error: Cannot redeclare. Usa require_once para archivos de funciones (lo verás en Include y plantillas).

Error común

Olvidar return. Si la función no devuelve nada, el resultado es null y tu echo no muestra nada. Declarar el tipo de retorno (: string) hace que PHP te avise.

Ejercicios ​

  1. Crea esPalindromo(string $texto): bool que ignore mayúsculas y espacios ('Anita lava la tina' → true).
  2. Crea promedio(float ...$numeros): float que devuelva 0 si no recibe números.
  3. Usando array_map y una función flecha, convierte ['ana', 'LUIS', 'sOfÍa'] en ['Ana', 'Luis', 'Sofía'] (pista: mb_convert_case).
Ver solución
php
<?php
declare(strict_types=1);

function esPalindromo(string $texto): bool
{
    $limpio = mb_strtolower(str_replace(' ', '', $texto), 'UTF-8');
    // mb_str_split + array_reverse invierte respetando acentos
    $invertido = implode('', array_reverse(mb_str_split($limpio)));
    return $limpio === $invertido;
}

var_dump(esPalindromo('Anita lava la tina')); // true
var_dump(esPalindromo('Hola'));               // false
php
<?php
declare(strict_types=1);

function promedio(float ...$numeros): float
{
    if (count($numeros) === 0) {
        return 0;
    }
    return array_sum($numeros) / count($numeros);
}

echo promedio(8, 9, 10); // 9
echo promedio();         // 0
php
<?php
$nombres = ['ana', 'LUIS', 'sOfÍa'];
$bonitos = array_map(fn($n) => mb_convert_case($n, MB_CASE_TITLE, 'UTF-8'), $nombres);
print_r($bonitos); // ['Ana', 'Luis', 'Sofía']

Resumen ​

  • Define funciones con function nombre(tipo $param): tipoRetorno.
  • Tipa siempre parámetros y retornos; usa ?tipo, uniones int|float, void y never.
  • Valores por defecto al final; llama con parámetros con nombre cuando aporte claridad.
  • ...$args recibe varios argumentos; ...$array los desempaqueta.
  • Las funciones no ven variables externas: pásalas como parámetros.
  • Closures con use; funciones flecha fn() => para expresiones cortas.
  • Agrupa tus utilidades en un helpers.php.

Academia Web — aprende, copia y construye.