Lección 7: Funciones

Cuando utilizamos en multiples ocasiones un mismo fragmento de código debemos usar funciones (functions). Una herramienta para encapsular y ejecutar un mismo código. Entre sus ventajas veremos que nos ayuda a que los ficheros tengan un menor tamaño y sea más fácil de mantener.

// Declarar
function nombre_de_funcion(tipo_de_parametro $parametros): tipo_return
{
    ...
    return ...;
}

// Llamar
nombre_de_funcion($parametros);

En el ejemplo inferior tenemos una función clásica, con sintáxis moderna, donde es declarada y ejecutada seguido de un echo para ver el resultado. Lo único que hace es devolver un texto cuando es llamado.

/**
 * Función con educación
 * @return {string}
 */
function saludar_ahora(): string
{
    return 'Hola, soy una función';
}
echo saludar_ahora();
// Hola, soy una función

La receta par hacer una función rica y con fundamento:

  • Las 4 primeras líneas es el formato de comentarios. Una función, por mucha prisa que tengas, debe estar comentada con el formato del ejemplo.
  • La palabra function esta reservada. A continuación el nombre, que debe estar en minúsculas con guiones bajos en lugar de espacios. Después unos paréntesis con los argumentos. Si no tiene, se dejan vacíos pero siempre presentes. Luego dos puntos. Por último el tipo de valor resultante. Más abajo te he dejado una tabla con tipos admitidos.
  • Llaves para envolver tu código {}.
  • Y dentro la palabra reservada return seguido del valor a devolver.

Parámetros

Nuestras funciones serán más interesantes si les damos algunos parámetros. Al darle variables podemos usar siempre el mismo código pero con algunas variaciones.

/**
 * Corta un texto a 10 letras y añade puntos suspensivos al final
 * @param {string} $text - Texto a tratar
 * @return {string}
 */
function resumen(string $text): string
{
    return substr($text, 0, 20) . '...';
}

echo resumen('Cuanto te vi me enamoré y tu sonreíste porque lo sabías');
echo resumen('La vida es una historia contada por un idiota, una historia llena de estruendo y furia, que nada significa');
// Cuanto te vi me enam...
// La vida es una histo...

Si no se cumple los tipos en PHP 5 produce un error que para la ejecución. En cambio, en PHP 7, se lanza una excepción TypeError pero continua.

Nuestros parámetros de entrada pueden tener un valor por defecto.

/**
 * Saluda a una persona
 * @param {string} - Nombre
 * @return {string}
 */
function saludar(string $nombre = 'Anónimo'): string
{
    return 'Hola, persona llamada ' . $nombre .'. Por lo que veo tu nombre mide ' . strlen($nombre) . ' carácteres.';
}
echo saludar();
// Hola, persona llamada Anónimo. Por lo que veo tu nombre mide 8 carácteres.
echo saludar('Picasso');
// Hola, persona llamada Picasso. Por lo que veo tu nombre mide 7 carácteres.

Y, por supuesto, podemos añadir varios parámetros.

/**
 * Saluda a una persona
 * @param {string} - Nombre
 * @param {string} - Profesión
 * @return {string}
 */
function saludar(string $nombre = 'Anónimo', string $profesion = 'ninguna'): string
{
    return 'Hola, persona llamada ' . $nombre .'. Por lo que veo tu nombre mide ' . strlen($nombre) . ' carácteres. De profesión ' . $profesion . '.';
}
echo saludar();
// Hola, persona llamada Anónimo. Por lo que veo tu nombre mide 8 carácteres. De profesión ninguna.
echo saludar('Espartaco');
// Hola, persona llamada Espartaco. Por lo que veo tu nombre mide 9 carácteres. De profesión ninguna.
echo saludar('Picasso', 'pintor');
// Hola, persona llamada Picasso. Por lo que veo tu nombre mide 7 carácteres. De profesión pintor.

Tipos admitidos

Tipo Descripción Versión mínima
string El parámetro debe ser un string. PHP 7.0.0
int El parámetro debe ser un valor de tipo integer. PHP 7.0.0
float El parámetro debe ser un número de tipo float. PHP 7.0.0
bool El parámetro debe ser un valor de tipo boolean. PHP 7.0.0
array El parámetro debe ser un array. PHP 5.1.0
callable El parámetro debe ser un callable válido. PHP 5.4.0
self El parámetro debe ser una instanceof de la misma clase donde está definido el método. Esto solamente se puede utilizar en clases y métodos de instancia. PHP 5.0.0
nombre de clase/interfaz El parámetro debe ser una instanceof del nombre de la clase o interfaz dada. PHP 5.0.0

Más información

De forma automática PHP arreglará las incompatibilidades de tipos.

function incrementar(int $num): int
{
    return $num + 1;
}

echo incrementar(4.5);
// 5

Pero si quieres ser estricto deberás desactivar esta ayuda. En otras palabras, que si encuentra algún problema de tipos muestre un error y no aplique una mágica solución.

declare(strict_types=1);

function incrementar(int $num): int
{
    return $num + 1;
}

echo incrementar(4.5);
// PHP Fatal error:  Uncaught TypeError: Argument 1 passed to incrementar() must be of the type int, float given

Return con tipos alternativos

A partir de la versión 7.1 de PHP disponemos de la posibilidad de indicar si un return devuelve un tipo concreto o un null. Para ello solo habrá que añadir un interrogante en su inicio.

function nombre(): ?string
{
 
}

En el siguiente ejemplo podremos devolver un string o un null. Dependiendo de si el ganador esta entre los 3 primeros o no.

/**
 * Método que indica el tipo de metal que debe tener una medalla a partir del resultado
 * @param {int} $posicion - Posición
 * @return {string|null} - Tipo de metal
 */
function tipoDeMedalla(int $posicion): ?string
{
    switch ($posicion) {
        case 1:
            return 'Oro';
        case 2:
            return 'Plata';
        case 3:
            return 'Bronce';
        default:
            return null;
    }
}

echo tipoDeMedalla(2);
// Plata

echo tipoDeMedalla(34);
// null

Tal vez fue añadido esta característica por lo práctico que resulta al realizar testing.

Y de la versión PHP 8 se enriquece más las posibilidades ya que es posible indicar 2 tipos diferentes.

function nombre(): int|string
{
 
}

Nos puede ayudar en casos como, por ejemplo, dar un resultado alternativo o de seguridad.

/**
 * Método que duplica un número en positivo
 * @param {int} $numero - Número a duplicar
 * @return {float|string} - Resultado o mensaje de ayuda
 */
function duplicarPositivo(float $numero): float|string
{
    if ($numero > 0) {
        return $numero * 2;
    } else {
        return 'No puedes usar número en negativo o cero';
    }
}

echo duplicarPositivo(12.1);
// 24.2

echo duplicarPositivo(-45);
// 'No puedes usar número en negativo o cero'

Anónimas

Las funciones anónimas son cerradas y pueden ser declaradas sin ningún nombre. Son obligatorias cuando tengamos que pasar una función como un parámetro de otra.

function () {
    return 'Soy anónima';
}

En el siguiente ejemplo incrementamos en 1 cada número del array.

$numeros = [10, 20, 30, 40];
$numerosIncrementados = array_map(function ($numero) {
    return $numero + 1;
}, $numeros);

var_dump($numerosIncrementados);

/*
array(4) {
  [0]=>
  int(11)
  [1]=>
  int(21)
  [2]=>
  int(31)
  [3]=>
  int(41)
}
*/

Usar variables externas

Si vas a usar variables que están presentes en tu código, puedes enriquecer el contenido de la función usando use.

$tienda = 'pescadería';

function () use ($tienda) {
    return "Estoy en la $tienda";
}

Paradigma Funcional

Las funciones esenciales para iterar y gestionar un array son: filter, map y reduce. Por supuesto también es posible trabajar con ellas dentro de PHP, además de iterar sin recurrir a un bucle (sí, se puede programar sin bucles).

Iterar

Recorre un array, similar a un foreach.

array_walk({array}, {función});

En este ejemplo vamos a imprimir todas las ciudades.

<?php

// Diccionario
$apartamentos = [
    [
        'precio/noche' => 40,
        'ciudad' => 'Valencia',
        'wifi' => True,
        'pagina web' => 'https://hotel.com'
    ],
    [
        'precio/noche' => 87,
        'ciudad' => 'Calpe',
        'wifi' => True,
        'pagina web' => 'https://calpe.com'
    ],
    [
        'precio/noche' => 67,
        'ciudad' => 'Valencia',
        'wifi' => False,
        'pagina web' => 'https://denia.com'
    ],
    [
        'precio/noche' => 105,
        'ciudad' => 'Benidorm',
        'wifi' => False,
        'pagina web' => 'https://benidorm.com'
    ]
];

array_walk($apartamentos, function ($apartamento, $posicion) {
    echo $apartamento['ciudad'] . PHP_EOL;
});

/*
Valencia
Calpe
Valencia
Benidorm
*/

Filter

Obtenemos un array a otro más pequeño.

array_filter({array}, {función});

En este ejemplo filtraremos $apartamentos para quedarnos con los que están en Valencia.

<?php

// Diccionario
$apartamentos = [
    [
        'precio/noche' => 40,
        'ciudad' => 'Valencia',
        'wifi' => True,
        'pagina web' => 'https://hotel.com'
    ],
    [
        'precio/noche' => 87,
        'ciudad' => 'Calpe',
        'wifi' => True,
        'pagina web' => 'https://calpe.com'
    ],
    [
        'precio/noche' => 67,
        'ciudad' => 'Valencia',
        'wifi' => False,
        'pagina web' => 'https://denia.com'
    ],
    [
        'precio/noche' => 105,
        'ciudad' => 'Benidorm',
        'wifi' => False,
        'pagina web' => 'https://benidorm.com'
    ]
];


$todosLosApartamentosValencia = array_filter($apartamentos, function ($apartamento) {
    return $apartamento['ciudad'] === 'Valencia';
});

var_dump($todosLosApartamentosValencia);

/*
array(2) {                                                                  
  [0]=>                                                                     
  array(4) {                                                                
    ["precio/noche"]=>   
    int(40)
    ["ciudad"]=>
    string(8) "Valencia"
    ["wifi"]=>
    bool(true)
    ["pagina web"]=>
    string(17) "https://hotel.com"
  }
  [2]=>
  array(4) {
    ["precio/noche"]=>
    int(67)
    ["ciudad"]=>
    string(8) "Valencia"
    ["wifi"]=>
    bool(false)
    ["pagina web"]=>
    string(17) "https://denia.com"
  }
}
*/

Map

Transforma el contenido de un array pero mantiene el número de elementos.

array_map({función}, {array});

En este ejemplo vamos a reducir el precio por noche en 1.

<?php

// Diccionario
$apartamentos = [
    [
        'precio/noche' => 40,
        'ciudad' => 'Valencia',
        'wifi' => True,
        'pagina web' => 'https://hotel.com'
    ],
    [
        'precio/noche' => 87,
        'ciudad' => 'Calpe',
        'wifi' => True,
        'pagina web' => 'https://calpe.com'
    ],
    [
        'precio/noche' => 67,
        'ciudad' => 'Valencia',
        'wifi' => False,
        'pagina web' => 'https://denia.com'
    ],
    [
        'precio/noche' => 105,
        'ciudad' => 'Benidorm',
        'wifi' => False,
        'pagina web' => 'https://benidorm.com'
    ]
];

$apartamentosMasBaratos = array_map(function ($apartamento) {
    return array_merge($apartamento, ['precio/noche' => $apartamento['precio/noche'] - 1]);
}, $apartamentos);

var_dump($todosLosApartamentosValencia);
/*
array(4) {
  [0]=>
  array(4) {
    ["precio/noche"]=>
    int(39)
    ["ciudad"]=>
    string(8) "Valencia"
    ["wifi"]=>
    bool(true)
    ["pagina web"]=>
    string(17) "https://hotel.com"
  }
  [1]=>
  array(4) {
    ["precio/noche"]=>
    int(86)
    ["ciudad"]=>
    string(5) "Calpe"
    ["wifi"]=>
    bool(true)
    ["pagina web"]=>
    string(17) "https://calpe.com"
  }
  [2]=>
  array(4) {
    ["precio/noche"]=>
    int(66)
    ["ciudad"]=>
    string(8) "Valencia"
    ["wifi"]=>
    bool(false)
    ["pagina web"]=>
    string(17) "https://denia.com"
  }
  [3]=>
  array(4) {
    ["precio/noche"]=>
    int(104)
    ["ciudad"]=>
    string(8) "Benidorm"
    ["wifi"]=>
    bool(false)
    ["pagina web"]=>
    string(20) "https://benidorm.com"
  }
}
*/

Reduce

Obtiene un resultado a partir de un array.

array_reduce({array}, {función}, {inicial});

En este ejemplo vamos calcular cual es la media del precio por noche.

<?php

// Diccionario
$apartamentos = [
    [
        'precio/noche' => 40,
        'ciudad' => 'Valencia',
        'wifi' => True,
        'pagina web' => 'https://hotel.com'
    ],
    [
        'precio/noche' => 87,
        'ciudad' => 'Calpe',
        'wifi' => True,
        'pagina web' => 'https://calpe.com'
    ],
    [
        'precio/noche' => 67,
        'ciudad' => 'Valencia',
        'wifi' => False,
        'pagina web' => 'https://denia.com'
    ],
    [
        'precio/noche' => 105,
        'ciudad' => 'Benidorm',
        'wifi' => False,
        'pagina web' => 'https://benidorm.com'
    ]
];

$media = array_reduce($apartamentos, function ($acumulador, $apartamento) {
    return $apartamento['precio/noche'] + $acumulador;
}, 0) / count($apartamentos);

echo $media;
// 74.75
¿Te ha gustado? Comprame un café

Comentarios

{{ comments.length }} comentarios

Nuevo comentario

Nueva replica  {{ formatEllipsisAuthor(replyComment.author) }}

Acepto la política de Protección de Datos.

Escribe el primer comentario