Funciones

La firma de una función es un contrato

Marco González Luengo

Tabla de contenidos
  1. Definir una función
  2. strict_types: los tipos se hacen cumplir
  3. Puede devolver null: ?int
  4. Una función no ve lo de afuera
  5. Encadenar funciones con |>
  6. Para practicar

Las funciones en PHP se parecen mucho a las de Python. La gran diferencia es que aquí los tipos no son un adorno: si los declaras, PHP los hace cumplir.

Definir una función

<?php
declare(strict_types=1);

function promedio(array $ns): float {
    return array_sum($ns) / count($ns);
}

echo promedio([6.0, 5.5, 4.8]), PHP_EOL;

strict_types: los tipos se hacen cumplir

En Python, los type hints son documentación y nadie los revisa al ejecutar. En PHP, con declare(strict_types=1) en la primera línea del archivo, el motor los verifica en cada llamada:

<?php
declare(strict_types=1);

function doble(float $x): float {
    return $x * 2;
}

var_dump(doble(6));      // un int sí se acepta donde se pide float
var_dump(doble("6.0"));  // con strict_types, un string no pasa

Prueba a borrar la línea del declare y ejecutar de nuevo: PHP convierte "6.0" a número por su cuenta y el programa sigue como si nada.

¿Por qué insistir con esto?

Puede devolver null: ?int

Un ? antes del tipo lo hace nullable: la función puede devolver ese tipo o null. Combinado con ?? (que vimos en Arrays), queda algo muy expresivo:

<?php
declare(strict_types=1);

function buscarStock(array $inventario, string $producto): ?int {
    return $inventario[$producto] ?? null;
}

$stock = ["arroz" => 12];
var_dump(buscarStock($stock, "arroz"));   // int(12)
var_dump(buscarStock($stock, "azúcar"));  // NULL, sin warning

Leyendo solo la firma (array $inventario, string $producto): ?int) ya sabes qué entra, qué sale y que puede no encontrar nada. Eso es código mantenible.

Una función no ve lo de afuera

En Python, una función puede leer variables globales. En PHP, no: dentro de una función solo existen sus parámetros y las variables que cree ella misma. Es el ámbito de las variables.

<?php
$sala = [
    'lunes' => 'A202',
    'jueves' => 'C304',
];

// Sin parámetro: la función no ve $sala
function leermeSinParametro() {
    echo $sala['jueves'], PHP_EOL;
}

// Con parámetro: ahora sí
function leerme($salon) {
    echo $salon['jueves'], PHP_EOL;
}

leermeSinParametro();
leerme($sala);

Esto que parece una molestia en realidad es una ayuda: todo lo que la función necesita está a la vista en su firma.

Ojo, que hay un segundo detalle: lo que entra por parámetro es una copia. Si la función modifica el array que recibió, el de afuera no cambia. Cómo hacer que sí cambie (y cuándo conviene) está en Parámetros por referencia.

Encadenar funciones con |>

PHP 8.5 trajo el operador pipe |>, que pasa el resultado de una función a la siguiente, de izquierda a derecha, en vez de anidarlas hacia adentro:

<?php
declare(strict_types=1);

$titulo = "  Hola Mundo  ";

// Anidado: se lee de adentro hacia afuera
$slug1 = strtolower(trim($titulo));

// Con pipe: se lee en el orden en que ocurre
$slug2 = $titulo
    |> trim(...)
    |> strtolower(...);

var_dump($slug1, $slug2);

El trim(...) con tres puntos es la forma de referirse a la función misma, sin llamarla todavía.

Para practicar

  1. Una función promedio que reciba una lista de notas y devuelva el promedio. ¿Qué pasa si la lista viene vacía? (Spoiler en Probar algoritmos.)
  2. Una función que reciba una lista de números y devuelva solo los mayores que un límite. Hazla primero con foreach, y después mira array_filter.
<?php
declare(strict_types=1);

// Escribe tu solución aquí y presiona ▶ Ejecutar


Sigue con Devolver valores con return.