Funciones en PHP
En esta lección
- Definir y llamar a una función
- Parámetros y return
- Tipos en parámetros y retorno
- Valores por defecto
- Argumentos con nombre
- Número variable de argumentos
- Paso por valor y por referencia
- Ámbito de las variables
- Funciones anónimas y closures
- Funciones flecha
- Recursividad
- Ejemplo completo: precio de una reserva
- Errores frecuentes
- Resumen
Una función es un bloque de código con nombre que puedes ejecutar tantas veces como quieras. En lugar de copiar el cálculo del precio con IVA en diez páginas, lo escribes una vez dentro de una función y lo llamas donde haga falta; si cambia el IVA, lo cambias en un único sitio. En esta lección aprenderás a definir funciones con tipos, a devolver resultados, a usar valores por defecto y argumentos con nombre, a entender el ámbito de las variables y a crear funciones anónimas y funciones flecha.
Definir y llamar a una función
Se define con la palabra function, un nombre, los paréntesis y el cuerpo entre llaves:
function saludar()
{
echo "¡Bienvenida al rocódromo!\n";
}
saludar();
saludar();
// ¡Bienvenida al rocódromo!
// ¡Bienvenida al rocódromo!
Definir una función no la ejecuta: solo le pone nombre al código. Se ejecuta cada vez que la llamas escribiendo su nombre seguido de paréntesis.
Sobre los nombres:
- En PHP moderno se escriben en camelCase y suelen empezar por un verbo:
calcularTotal,enviarCorreo,esMayorDeEdad. - A diferencia de las variables, los nombres de funciones no distinguen mayúsculas:
saludar()ySALUDAR()llaman a la misma. Aun así, escríbelos siempre igual. - No puedes definir dos funciones con el mismo nombre, ni usar el nombre de una función de PHP (
count,strlen…).
Puedes llamar a una función antes de la línea donde está definida, siempre que esté en el mismo archivo y no dentro de un if. Aun así, lo más claro es definirlas arriba o, mejor, en un archivo aparte, como verás en include y require.
Parámetros y return
Una función se vuelve útil cuando recibe datos y devuelve un resultado. Los parámetros son las variables que declaras entre paréntesis; los argumentos, los valores concretos que pasas al llamarla. Con return la función devuelve un valor y termina:
function precioConIva(float $precio, float $iva): float
{
return round($precio * (1 + $iva), 2);
}
$cuota = precioConIva(35, 0.21);
echo "Cuota mensual: $cuota €\n";
echo "Bono 10 sesiones: ", precioConIva(80, 0.21), " €\n";
// Cuota mensual: 42.35 €
// Bono 10 sesiones: 96.8 €
return o echo
Es la duda más común al empezar. Compara estas dos funciones:
function mostrarTotal(float $a, float $b): void
{
echo $a + $b, "\n";
}
function sumar(float $a, float $b): float
{
return $a + $b;
}
mostrarTotal(10, 5);
$total = sumar(10, 5) * 2;
echo $total, "\n";
// 15
// 30
mostrarTotal() imprime el resultado, pero no te lo da: no puedes guardarlo, multiplicarlo ni usarlo en una condición. sumar() lo devuelve y tú decides qué hacer con él. Regla práctica: las funciones calculan y devuelven; quien las llama decide si imprimir. Así sirven igual para una página HTML, para un JSON o para una prueba.
Detalles de return:
- Termina la función en el acto: lo que haya debajo no se ejecuta.
- Puedes tener varios
return, por ejemplo uno en cada rama de unif. - Solo devuelve un valor. Si necesitas varios, devuelve un array y desestructúralo:
[$min, $max] = rango($notas);. - Una función sin
returndevuelvenull.
Tipos en parámetros y retorno
Desde PHP 7, y mucho más desde PHP 8, puedes indicar el tipo de cada parámetro y el del valor devuelto (detrás de ):). No es obligatorio, pero es muy recomendable: documenta la función, el editor te avisa de errores y PHP detecta llamadas incorrectas.
| Tipo | Significado |
|---|---|
int, float, string, bool, array | Los tipos básicos |
?string | Una cadena o null (nullable) |
int|float | Un entero o un decimal (tipo unión) |
void | No devuelve nada (solo en el retorno) |
mixed | Cualquier cosa |
callable | Algo que se puede llamar, como una función |
function buscarSocio(array $socios, int $id): ?string
{
return $socios[$id] ?? null;
}
$socios = [7 => "Irene", 12 => "Unai"];
var_dump(buscarSocio($socios, 12));
var_dump(buscarSocio($socios, 99));
// string(4) "Unai"
// NULL
El ? delante de string avisa a quien use la función de que puede recibir null y debe tenerlo en cuenta.
Como viste en Variables y tipos, sin declare(strict_types=1); PHP convierte los argumentos cuando puede (la cadena "5" pasa como int). Con él, un tipo incorrecto lanza un TypeError. Ponlo al principio de tus archivos: es la forma moderna de trabajar.
Valores por defecto
Un parámetro puede tener un valor por defecto, que se usa si no le pasas ese argumento. Los parámetros con valor por defecto van al final:
function formatearPrecio(float $cantidad, string $moneda = "€", int $decimales = 2): string
{
return number_format($cantidad, $decimales, ",", ".") . " " . $moneda;
}
echo formatearPrecio(1250.5), "\n";
echo formatearPrecio(1250.5, "USD"), "\n";
echo formatearPrecio(1250.5, "€", 0), "\n";
// 1.250,50 €
// 1.250,50 USD
// 1.251 €
Argumentos con nombre
En la última llamada hemos tenido que repetir "€" solo para llegar al tercer parámetro. PHP 8 permite pasar argumentos por su nombre, en cualquier orden y saltándote los que tienen valor por defecto:
echo formatearPrecio(1250.5, decimales: 0), "\n";
echo formatearPrecio(moneda: "£", cantidad: 99), "\n";
// 1.251 €
// 99,00 £
Además de ahorrar argumentos, hacen las llamadas más legibles. Compara crearReserva("Ane", 4, true, false) con crearReserva("Ane", personas: 4, terraza: true, aviso: false). Funcionan también con las funciones de PHP: htmlspecialchars($texto, double_encode: false).
Número variable de argumentos
Si antepones ... al último parámetro, recoge todos los argumentos sobrantes en un array. Es un parámetro variádico:
function media(float ...$numeros): float
{
if (count($numeros) === 0) {
return 0;
}
return array_sum($numeros) / count($numeros);
}
echo media(7, 8.5, 6), "\n";
echo media(), "\n";
$notas = [9, 10, 8];
echo media(...$notas), "\n";
// 7.1666666666667
// 0
// 9
En la última llamada, ... hace lo contrario: desempaqueta el array para pasar cada elemento como un argumento separado.
Paso por valor y por referencia
Cuando pasas una variable a una función, PHP le pasa una copia de su valor. Lo que haga la función con su parámetro no afecta a la variable original. Esto vale también para los arrays:
function anadirExtra(array $carrito): array
{
$carrito[] = "Magnesio";
return $carrito;
}
$miCarrito = ["Cuerda"];
$nuevo = anadirExtra($miCarrito);
echo count($miCarrito), " y ", count($nuevo), "\n";
// 1 y 2
Si pones & delante del parámetro, la función recibe una referencia a la variable original y puede modificarla. Así funcionan sort() y compañía, como viste en Funciones de arrays:
function aplicarDescuento(float &$precio, float $porcentaje): void
{
$precio = $precio * (1 - $porcentaje / 100);
}
$precio = 60;
aplicarDescuento($precio, 25);
echo $precio, "\n";
// 45
Úsalo poco. Una función que devuelve un resultado nuevo es más fácil de entender y de probar que una que cambia variables “a escondidas”.
Ámbito de las variables
El ámbito (scope) es la zona del código donde existe una variable. En PHP la regla es estricta: dentro de una función solo existen sus parámetros y las variables que cree ella misma. No ve las variables de fuera:
$iva = 0.21;
function totalConIva(float $base): float
{
return $base * (1 + $iva);
}
echo totalConIva(100), "\n";
// Warning: Undefined variable $iva in ...
// 100
Esto sorprende si vienes de JavaScript, pero es una ventaja: una función no puede depender por accidente de una variable que alguien cambió en otra parte del programa. La solución correcta es pasarle lo que necesita como parámetro (o usar una constante, que sí es visible en todas partes).
En código antiguo verás la palabra global (global $iva;) o el array $GLOBALS para acceder a variables de fuera. Evítalos: hacen el código difícil de seguir.
Variables static
Las variables locales se crean al entrar en la función y desaparecen al salir. Una variable declarada con static conserva su valor entre llamadas:
function siguienteTicket(): int
{
static $numero = 0;
$numero++;
return $numero;
}
echo siguienteTicket(), " ", siguienteTicket(), " ", siguienteTicket(), "\n";
// 1 2 3
El valor inicial (= 0) solo se asigna la primera vez. Recuerda que en una web cada petición empieza de cero: static no sirve para contar visitas entre usuarios, solo dentro de una misma ejecución.
Funciones anónimas y closures
Una función anónima es una función sin nombre que puedes guardar en una variable o pasar como argumento. Es justo lo que necesitan usort(), array_map() o array_filter():
$conEuro = function (float $n): string {
return number_format($n, 2, ",", ".") . " €";
};
echo $conEuro(19.9), "\n";
echo implode(" / ", array_map($conEuro, [5, 12.5])), "\n";
// 19,90 €
// 5,00 € / 12,50 €
Fíjate en el ; tras la llave de cierre: es una asignación.
Las funciones anónimas tampoco ven las variables de fuera. Para usar una, tienes que capturarla con use. A una función que captura variables de su entorno se le llama closure:
$minimo = 18;
$adultos = array_filter(
["Ane" => 17, "Hugo" => 34, "Olga" => 18],
function (int $edad) use ($minimo): bool {
return $edad >= $minimo;
}
);
echo implode(", ", array_keys($adultos)), "\n";
// Hugo, Olga
use captura una copia del valor en el momento de crear la función. Si después cambias $minimo, la función no se entera.
Funciones flecha
Las funciones flecha (PHP 7.4) son la forma corta de una función anónima de una sola expresión. Se escriben con fn, no llevan llaves ni return y capturan automáticamente las variables de fuera:
$minimo = 18;
$edades = ["Ane" => 17, "Hugo" => 34, "Olga" => 18];
$adultos = array_filter($edades, fn(int $edad): bool => $edad >= $minimo);
echo implode(", ", array_keys($adultos)), "\n";
$duplicar = fn($n) => $n * 2;
echo $duplicar(21), "\n";
// Hugo, Olga
// 42
function () use (...) { } | fn() => ... | |
|---|---|---|
| Cuerpo | Varias instrucciones | Una sola expresión |
return | Obligatorio | Implícito |
| Variables de fuera | Solo las indicadas en use | Todas, automáticamente (por valor) |
| Uso típico | Lógica de varias líneas | Callbacks cortos en array_map, usort… |
Una función que recibe otra función como argumento, como array_map, se llama función de orden superior, y la función que le pasas, callback. Puedes escribir las tuyas con el tipo callable:
function aplicarATodos(array $datos, callable $transformar): array
{
$resultado = [];
foreach ($datos as $clave => $valor) {
$resultado[$clave] = $transformar($valor);
}
return $resultado;
}
print_r(aplicarATodos(["a" => "hola", "b" => "adiós"], 'strtoupper'));
// Array
// (
// [a] => HOLA
// [b] => ADIóS
// )
¿Y esa ó minúscula? strtoupper() solo entiende letras sin tilde. Para textos en español usa mb_strtoupper(), que verás en Cadenas.
Recursividad
Una función recursiva es la que se llama a sí misma. Necesita un caso base que detenga las llamadas; si no, se repetiría hasta agotar la memoria:
function cuentaAtras(int $n): void
{
if ($n === 0) {
echo "¡Ya!\n";
return;
}
echo $n, "... ";
cuentaAtras($n - 1);
}
cuentaAtras(3);
// 3... 2... 1... ¡Ya!
Es útil con estructuras anidadas, como un menú con submenús o un árbol de carpetas. Para contar o recorrer listas, un bucle suele ser más claro.
Ejemplo completo: precio de una reserva
declare(strict_types=1);
const IVA = 0.21;
function precioReserva(
int $personas,
float $precioPorPersona,
bool $esSocio = false,
?string $codigo = null,
): array {
$base = $personas * $precioPorPersona;
$descuento = match (true) {
$esSocio => 0.15,
$codigo === "VERANO" => 0.10,
default => 0,
};
$neto = $base * (1 - $descuento);
return [
"base" => round($base, 2),
"descuento" => round($base - $neto, 2),
"total" => round($neto * (1 + IVA), 2),
];
}
$reserva = precioReserva(4, 12.0, codigo: "VERANO");
echo "Base: {$reserva['base']} €, descuento: {$reserva['descuento']} €, total: {$reserva['total']} €\n";
["total" => $total] = precioReserva(2, 12.0, esSocio: true);
echo "Socio, 2 personas: $total €\n";
// Base: 48 €, descuento: 4.8 €, total: 52.27 €
// Socio, 2 personas: 24.68 €
La coma después del último parámetro está permitida desde PHP 8 y facilita añadir parámetros nuevos. El match lo viste en Condicionales.
Errores frecuentes
- Imprimir en lugar de devolver: si la función hace
echo, no podrás usar su resultado. Devuelve conreturny deja que quien llama decida. - Usar una variable de fuera dentro de la función: da Undefined variable. Pásala como parámetro o captúrala con
use. - Poner un parámetro opcional antes de uno obligatorio:
function f($a = 1, $b)está obsoleto en PHP 8. Los opcionales van al final. - Olvidar el
;al guardar una función anónima en una variable:$f = function () { ... };. - Esperar que la función cambie el array que le pasas: recibe una copia. Devuelve el array nuevo (o usa
&si de verdad lo necesitas). - Funciones demasiado largas: si no cabe en la pantalla o hace tres cosas distintas, divídela en varias.
Resumen
| Concepto | Ejemplo |
|---|---|
| Definir | function sumar(int $a, int $b): int { return $a + $b; } |
| Llamar | $total = sumar(2, 3); |
| Sin valor de retorno | function mostrar(): void { ... } |
| Nullable y unión | ?string, int|float |
| Valor por defecto | function f(string $moneda = "€") |
| Argumentos con nombre | formatearPrecio(99, decimales: 0) |
| Variádicos | function media(float ...$n) y media(...$array) |
| Por referencia | function f(array &$a) |
| Ámbito | Dentro solo existen los parámetros y las variables locales |
static | Conserva el valor entre llamadas |
| Anónima / closure | function ($x) use ($y) { return ...; } |
| Flecha | fn($x) => $x * 2 |
En la siguiente lección aprenderás a repartir tu código en varios archivos: include y require.
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.