Skip to the content.

PHP Moderno Cheatsheet

PHP Moderno Cheatsheet

Si te gusta este contenido, podés contactarme o seguirme en Twitter. :+1:

Tweet for help

Traducción por: Cristian Ferreyra backendrulz

Nota de traducción: Elegí no traducir algunos términos ya que son extremadamente técnicos y podrían dificultar el aprendizaje de futuros lectores.

Introducción

Motivación

Este documento es un cheatsheet para PHP con código que encontrará con frecuencia en proyectos modernos.

Esta guía no está destinada a enseñarte PHP desde cero, sino a ayudar a los desarrolladores con conocimientos básicos que pueden tener dificultades para familiarizarse con las bases de código modernas (o para aprender Laravel o Symfony, por ejemplo) debido a los nuevos conceptos y características que PHP ha introducido a lo largo de los años.

Nota: Los conceptos presentados acá se basan en la versión más reciente de PHP disponible (PHP 8.1 en el momento de la última actualización)

Recursos complementarios

Cuando tengas dificultad para comprender un concepto, te sugiero que busques respuestas en los siguientes sitios:

Lanzamientos recientes de PHP

Version Fecha de lanzamiento
PHP 8.2 Diciembre 2022
PHP 8.1 Noviembre 2021
PHP 8.0 Noviembre 2020
PHP 7.4 Noviembre 2019
PHP 7.3 Diciembre 2018
PHP 7.2 Noviembre 2017
PHP 7.1 Diciembre 2016
PHP 7.0 Diciembre 2015

Mas información en php.net.

Tabla de contenidos

Fundamentos

Parámetro por defecto de función

Podés establecer un valor predeterminado para tus parámetros de función:

function myFunction($param = 'foo')
{
    return $param;
}
$a = myFunction();
// $a = 'foo'

$b = myFunction('bar');
// $b = 'bar'

Pero si enviás una propiedad nula o indefinida, no se utilizará el valor predeterminado:

function myFunction($param = 'foo')
{
    return $param;
}
$a = myFunction(null);
// $a = null

$b = myFunction($undefined); // PHP Warning:  Undefined variable $undefined
// $b = null

Coma final

Una coma final es un símbolo de coma que se escribe después del último elemento de una lista de elementos. Uno de los principales beneficios cuando se usa con multilíneas es que las diferencias son más limpias.

Matriz

Podés usar una coma final en matrices:

$array = [
    'foo',
    'bar',
];

Declaración de uso agrupado

php-version-72

Desde PHP 7.2, podés usar una coma final en declaraciones de uso agrupadas:

use Symfony\Component\HttpKernel\{
    Controller\ControllerResolverInterface,
    Exception\NotFoundHttpException,
    Event\PostResponseEvent,
};

Llamada de función y método

php-version-73

Desde PHP 7.3, podés usar una coma final al llamar a una función:

function myFunction($foo, $bar)
{
    return true;
}
$a = myFunction(
    'baz',
    'qux',
);

y al llamar a un método:

$f = new Foo();
$f->myMethod(
    'baz',
    'qux',
);

Parámetros de función

php-version-80

Desde PHP 8.0, podés usar una coma final al declarar los parámetros de una función:

function myFunction(
    $foo,
    $bar,
)
{
    return true;
}

Declaración de uso

php-version-80

Desde PHP 8.0, podés usar una coma final en la declaración de uso:

function() use (
    $foo,
    $bar,
)
{
    return true;
}

Declaración de tipo

php-version-70

Con la declaración de tipo, se puede especificar el tipo de datos esperado para una propiedad que se aplicará en tiempo de ejecución. Admite muchos tipos, como tipos escalares (int, string, bool y float), pero también array, iterable, object, stdClass, etc.

Podés establecer un tipo para el parámetro de una función:

function myFunction(int $param)
{
    return $param;
}
$a = myFunction(10);
// $a = 10
$b = myFunction('foo'); // TypeError: myFunction(): Argument #1 ($param) must be of type int, string given

También se puede establecer un tipo de retorno para una función:

function myFunction() : int
{
    return 'foo';
}
$a = myFunction(); // TypeError: myFunction(): Return value must be of type int, string returned

Cuando una función no debería devolver algo, se puede usar el tipo “void”:

function myFunction() : void
{
    return 'foo';
}
// PHP Fatal error:  A void function must not return a value

Tampoco puede devolver null:

function myFunction() : void
{
    return null;
}
// PHP Fatal error:  A void function must not return a value

Sin embargo, usar return para salir de la función es válido:

function myFunction() : void
{
    return;
}
$a = myFunction();
// $a = null

Propiedad de clase

php-version-74

Podés establecer un tipo en una propiedad de clase:

Class Foo()
{
    public int $bar;
}
$f = new Foo();
$f->bar = 'baz'; // TypeError: Cannot assign string to property Foo::$bar of type int

Tipo de unión

php-version-80

Podés utilizar un “tipo de unión” que acepte valores de varios tipos diferentes, en lugar de uno solo:

function myFunction(string|int|array $param) : string|int|array
{
    return $param;
}

También funciona con las propiedades de la clase:

Class Foo()
{
    public string|int|array $bar;
}

Tipo de intersección

php-version-81

Desde PHP 8.1, podés usar un “tipo de intersección” (también conocido como “puro”) que exige que un valor dado pertenezca a todos los tipos. Por ejemplo, este parámetro necesita implementar las interfaces Stringable y Countable:

function myFunction(Stringable&Countable $param): Stringable&Countable
{
    return $param;
}
Class Foo
{
    public function __toString() {
        return "something";
    }
}
myFunction(new Foo());
// TypeError: myFunction(): Argument #1 ($param) must be of type Stringable&Countable, Foo given

También funciona con propiedades de clase:

Class Foo
{
    public Stringable&Countable $bar;
}

El tipo de intersección solo admite clases e interfaces. Los tipos escalares (string, int, array, null, mixed, etc.) no están permitidos:

function myFunction(string&Countable $param)
{
    return $param;
}
// PHP Fatal error:  Type string cannot be part of an intersection type
Recurso externo

Tipo Nullable

php-version-71

Cuando un parámetro no tiene tipo, puede aceptar un valor nulo:

function myFunction($param)
{
    return $param;
}
$a = myFunction(null);
// $a = null

Pero tan pronto como un parámetro tenga un tipo, ya no aceptará un valor nulo y devolverá un error:

function myFunction(string $param)
{
    return $param;
}
$a = myFunction(null); // TypeError: myFunction(): Argument #1 ($param) must be of type string, null given

Si una función tiene un tipo de retorno, tampoco aceptará un valor nulo:

function myFunction() : string
{
    return null;
}
$a = myFunction(); // TypeError: myFunction(): Return value must be of type string, null returned

Podés hacer una declaración de tipo explícitamente “nullable”:

function myFunction(?string $param)
{
    return $param;
}
$a = myFunction(null);
// $a = null

o con un tipo de unión:

function myFunction(string|null $param)
{
    return $param;
}
$a = myFunction(null);
// $a = null

También funciona con el tipo de retorno:

function myFunction(?string $param) : ?string
{
    return $param;
}
// or
function myFunction(string|null $param) : string|null
{
    return $param;
}

Pero void no puede ser “nullable”:

function myFunction() : ?void
{
   // algún código
}
// PHP Fatal error:  Void type cannot be nullable

o

function myFunction() : void|null
{
   // algún código
}
// PHP Fatal error:  Void type cannot be nullable

Podés establecer un tipo que acepta valores null en una propiedad de clase:

Class Foo()
{
    public int|null $bar;
}
$f = new Foo();
$f->bar = null;
$a = $f->bar;
// $a = null

Desestructuración de matrices

Podés desestructurar matrices para extraer varios elementos en variables independientes.

Matriz indexada

php-version-40

Considerando una matriz indexada como:

$array = ['foo', 'bar', 'baz'];

Podés desestructurar la matriz usando la sintaxis de lista:

list($a, $b, $c) = $array;

// $a = 'foo'
// $b = 'bar'
// $c = 'baz'

O a partir de PHP 7.1, usando la sintaxis corta:

[$a, $b, $c] = $array;

// $a = 'foo'
// $b = 'bar'
// $c = 'baz'

Podés saltar elementos:

list(, , $c) = $array;

// $c = 'baz'

O a partir de PHP 7.1, usando la sintaxis corta:

[, , $c] = $array;

// $c = 'baz'

Cuando intentes desestructurar un índice que no existe, obtendrás una advertencia:

list($a, $b, $c, $d) = $array; // PHP Warning:  Undefined array key 3

// $a = 'foo'
// $b = 'bar'
// $c = 'baz'
// $d = null;

También podés intercambiar variables con asignaciones de desestructuración, considerando que tenés variables como:

$a = 'foo';
$b = 'bar';

Entonces, si necesitás intercambiar $a y $b en lugar de usar una variable temporal como esta:

$temp = $a;
$a = $b;
$b = $temp;

// $a = 'bar'
// $b = 'foo'

Podés intercambiarlas usando la sintaxis de lista:

list($a, $b) = [$b, $a];

// $a = 'bar'
// $b = 'foo'

O desde PHP 7.1, la sintaxis abreviada:

[$a, $b] = [$b, $a];

// $a = 'bar'
// $b = 'foo'

Matriz asociativa

php-version-71

Considerando una matriz asociativa (con clave de cadena) como:

$array = [
    'foo' => 'value1',
    'bar' => 'value2',
    'baz' => 'value3',
];

La sintaxis de la lista anterior no funcionará con una matriz asociativa y recibirá una advertencia:

list($a, $b, $c) = $array; // PHP Warning:  Undefined array key 0 ...

// $a = null
// $b = null
// $c = null

Pero desde PHP 7.1 (~ diciembre 2016), podés desestructurar la matriz con otra sintaxis basada en llaves:

list('foo' => $a, 'bar' => $b, 'baz' => $c) = $array;

// $a = 'value1'
// $b = 'value2'
// $c = 'value3'

O usando la sintaxis corta:

['foo' => $a, 'bar' => $b, 'baz' => $c] = $array;

// $a = 'value1'
// $b = 'value2'
// $c = 'value3'

También podés desestructurar solamente una parte de la matriz (el órden no importa):

['baz' => $c, 'foo' => $a] = $array;

// $a = 'value1'
// $c = 'value3'

Cuando trates de desestructurar una llave que no exista en la matriz, recibirás una advertencia:

list('moe' => $d) = $array; // PHP Warning:  Undefined array key "moe"

// $d = null

Null Coalescing

php-version-70

Desde PHP 7.0 (~ diciembre 2015), podés usar el operador null coalescing para proporcionar un respaldo cuando una propiedad es nula sin error ni advertencia:

$a = null;
$b = $a ?? 'fallback';

// $b = 'fallback'

Es equivalente a:

$a = null;
$b = isset($a) ? $a : 'fallback';
// $b = 'fallback'

También funciona cuando la propiedad es indefinida:

$a = $undefined ?? 'fallback';

// $a = 'fallback'

Cualquier otro valor de la propiedad no activará el respaldo (fallback):

'' ?? 'fallback'; // ''
0 ?? 'fallback'; // 0
false ?? 'fallback'; // false

Se puede encadenar el null coalescing varias veces:

$a = null;
$b = null;
$c = $a ?? $b ?? 'fallback';
// $c = 'fallback'

Operador Elvis

php-version-53

No se debe confundir con el operador ternario corto (también conocido como el operador elvis), que se introdujo en PHP 5.3:

$a = null;
$b = $a ?: 'fallback';

// $b = 'fallback'

El operador ternario corto es equivalente a:

$a = null;
$b = $a ? $a : 'fallback';
// $b = 'fallback'

El resultado entre null coalescing y el operador Elvis puede ser similar, pero también diferente para algunos valores específicos:

'' ?: 'fallback'; // 'fallback'
0 ?: 'fallback'; // 'fallback'
false ?: 'fallback'; // 'fallback'

Null coalescing en matriz

Si existe una clave de matriz, no se activa el respaldo:

$a = ['foo' => 'bar'];
$b = $a['foo'] ?? 'fallback';

// $b = 'bar'

Pero cuando la matriz no existe, se activa el respaldo sin error ni advertencia:

$a = null;
$b = $a['foo'] ?? 'fallback';

// $b = 'fallback'

O si la propiedad de la matriz no está definida, el respaldo se activa sin errores ni advertencias:

$b = $undefined['foo'] ?? 'fallback';

// $b = 'fallback'

Cuando existe una matriz pero no se puede encontrar la clave, se activa el respaldo sin error ni advertencia:

$a = [];
$b = $a['foo'] ?? 'fallback';

// $b = 'fallback'

También funciona con matrices indexadas:

$a = ['foo'];

// reminder: $a[0] = 'foo'

$b = $a[1] ?? 'fallback';

// $b = 'fallback'

También funciona con matrices anidadas. Si existe una clave de matriz anidada, no se activa el respaldo:

$a = [
   'foo' => [
      'bar' => 'baz'
   ]
];
$b = $a['foo']['bar'] ?? 'fallback';

// $b = 'baz'

Pero cuando no se puede encontrar la clave anidada, se activa el respaldo sin error ni advertencia:

$a = [
   'foo' => [
      'bar' => 'baz'
   ]
];
$b = $a['foo']['qux'] ?? 'fallback';

// $b = 'fallback'

Null coalescing en objeto

También podés usar el operador null coalescing con objectos.

Atributo del objeto

Si existe el atributo del objeto, no se activa el respaldo:

$a = (object)[
    'foo' => 'bar'
];
$b = $a->foo ?? 'fallback';

// $b = 'bar'

Pero cuando no se puede encontrar el atributo del objeto, se activa el respaldo sin error ni advertencia:

$a = (object)[
    'foo' => 'bar'
];
$b = $a->baz ?? 'fallback';

// $b = 'fallback'
Método de objeto

También podés utilizar el operador null coalescing en la llamada al método de un objeto. Si el método existe, entonces no se activa el respaldo:

class Foo
{
    public function bar()
    {
        return 'baz';
    }
}

$a = new Foo();
$b = $a->bar() ?? 'fallback';

// $b = 'baz'

Pero cuando el método del objeto devuelve nulo, se activa el respaldo sin error ni advertencia:

class Foo
{
    public function bar()
    {
        return null;
    }
}

$a = new Foo();
$b = $a->bar() ?? 'fallback';

// $b = 'fallback'

Si no se puede encontrar el método del objeto, null coalescing no funcionará y obtendrás un error:

class Foo
{
    public function bar()
    {
        return 'baz';
    }
}

$a = new Foo();
$b = $a->baz() ?? 'fallback'; // PHP Error:  Call to undefined method baz()
Método encadenado

Cuando se utilizan métodos encadenados en un objeto y no se puede encontrar un elemento intermediario, null coalescing no funcionará y obtendrás un error:

class Foo
{
    public function bar()
    {
        return (object)[];
    }
}

$a = new Foo();
$b = $a->bar()->baz() ?? 'fallback'; // PHP Error:  Call to undefined method baz()

Operador de asignación de Null Coalescing

php-version-74

Podés establecer un valor predeterminado para una propiedad cuando es nulo:

$a = null;
$a = $a ?? 'foo';
// $a = 'foo'

Desde PHP 7.4, podés usar el operador de asignación de null coalescing para hacer lo mismo:

$a = null;
$a ??= 'foo';
// $a = 'foo'

Operador Nullsafe

php-version-80

Cuando intentes leer una propiedad o llames a un método en nulo, devolverá una advertencia y un error:

$a = null;
$b = $a->foo; // PHP Warning:  Attempt to read property "foo" on null
// $b = null

$c = $a->foo(); // PHP Error:  Call to a member function foo() on null

Con el operador nullsafe, se pueden hacer ambas cosas sin advertencia ni error:

$a = null;
$b = $a?->foo;
// $b = null
$c = $a?->foo();
// $c = null

Se pueden encadenar varios operadores nullsafe:

$a = null;
$b = $a?->foo?->bar;
// $b = null
$c = $a?->foo()?->bar();
// $c = null

Una expresión está en cortocircuito desde el primer operador null-safe que encuentra un valor nulo:

$a = null;
$b = $a?->foo->bar->baz();
// $b = null

El operador nullsafe no tiene ningún efecto si el objetivo no es nulo:

$a = 'foo';
$b = $a?->bar; // PHP Warning:  Attempt to read property "bar" on string
// $b = null
$c = $a?->baz(); // PHP Error:  Call to a member function baz() on string

El operador Nullsafe no puede manejar las matrices correctamente, pero aún puede tener algún efecto:

$a = [];
$b = $a['foo']->bar;
// PHP Warning:  Undefined array key "foo"
// PHP Warning:  Attempt to read property "bar" on null
// $b = null

$c = $a['foo']?->bar; // PHP Warning:  Undefined array key "foo"
// $c = null

$d = $a['foo']->bar();
// PHP Warning:  Undefined array key "foo"
// PHP Error:  Call to a member function bar() on null

$e = $a['foo']?->bar(); // PHP Warning:  Undefined array key "foo"
// $e = null

No se puede usar el operador nullsafe para escribir, es de solo lectura:

$a = null;
$a?->foo = 'bar'; // PHP Fatal error:  Can't use nullsafe operator in write context

Operador Spread

Parámetro Variadic

php-version-56

Desde PHP 5.6 (~ agosto 2014), se puede agregar un parámetro variadic a cualquier función que te permita usar listas de argumentos con longitud variable:

function countParameters(string $param, string ...$options) : int
{

    foreach ($options as $option) {
        // podés iterar en $options
    }

    return 1 + count($options);
}

countParameters('foo'); // 1
countParameters('foo', 'bar'); // 2
countParameters('foo', 'bar', 'baz'); // 3

El parámetro variadic siempre debe ser el último parámetro declarado:

function countParameters(string ...$options, string $param)
{
   // algún código
}
// PHP Fatal error: Only the last parameter can be variadic

Solo se puede tener un parámetro variadic:

function countParameters(string ...$options, string ...$moreOptions)
{
   // algún código
}
// PHP Fatal error: Only the last parameter can be variadic

No puede tener un valor predeterminado:

function countParameters(string $param, string ...$options = [])
{
   // algún código
}
// PHP Parse error: Variadic parameter cannot have a default value

Cuando no es tipado, acepta cualquier valor:

function countParameters(string $param, ...$options) : int
{
    return 1 + count($options);
}

$a = countParameters('foo', null, [], true);
// $a = 4

Cuando es tipado, tenés que usar valores correctamente definidos:

function countParameters(string $param, string ...$options) : int
{
    return 1 + count($options);
}

countParameters('foo', null);
// TypeError: countParameters(): Argument #2 must be of type string, null given

countParameters('foo', []);
// TypeError: countParameters(): Argument #2 must be of type string, array given

Desempaquetando argumentos

php-version-56

Las matrices y los objetos traversable se pueden desempaquetar en listas de argumentos al llamar a funciones mediante el operador spread:

function add(int $a, int $b, int $c) : int
{
    return $a + $b + $c;
}
$array = [2, 3];
$r = add(1, ...$array);

// $r = 6

La matriz puede tener más elementos de los necesarios:

function add(int $a, int $b, int $c) : int
{
    return $a + $b + $c;
}
$array = [2, 3, 4, 5];
$r = add(1, ...$array);

// $r = 6

La matriz no puede tener menos elementos de los necesarios:

function add(int $a, int $b, int $c) : int
{
    return $a + $b + $c;
}
$array = [2];
$r = add(1, ...$array); // TypeError: Too few arguments to function add(), 2 passed

Excepto cuando algunos argumentos tienen un valor predeterminado:

function add(int $a, int $b, int $c = 0) : int
{
    return $a + $b + $c;
}
$array = [2];
$r = add(1, ...$array);
// $r = 3

Si un argumento es tipado y el valor no coincide con el tipo, obtendrás un error:

function add(int $a, int $b, int $c) : int
{
    return $a + $b + $c;
}
$array = ['foo', 'bar'];
$r = add(1, ...$array); // TypeError: add(): Argument #2 ($b) must be of type int, string given

Desde PHP 8.0, es posible desempaquetar una matriz asociativa ya que usará argumentos nombrados.

Desempaquetado de Matriz

Matriz indexada

php-version-74

Cuando se desea fusionar varias matrices, generalmente se usa array_merge:

$array1 = ['baz'];
$array2 = ['foo', 'bar'];

$array3 = array_merge($array1, $array2);
// $array3 = ['baz', 'foo', 'bar']

Pero desde PHP 7.4 (~ noviembre 2019), se pueden desempaquetar matrices indexadas con el operador spread:

$array1 = ['foo', 'bar'];
$array2 = ['baz', ...$array1];
// $array2 = ['baz', 'foo', 'bar']

Los elementos se fusionarán en el orden en que se pasen:

$array1 = ['foo', 'bar'];
$array2 = ['baz', ...$array1, "qux"];
// $array2 = ['baz', 'foo', 'bar', "qux"]

No se realiza ninguna deduplicación:

$array1 = ['foo', 'bar'];
$array2 = ['foo', ...$array1];
// $array2 = ['foo', 'foo', 'bar']

Se pueden desempaquetar varias matrices a la vez:

$array1 = ['foo', 'bar'];
$array2 = ['baz'];
$array3 = [ ...$array1, ...$array2];
// $array3 = ['foo', 'bar', 'baz']

Se puede desempaquetar la misma matriz varias veces:

$array1 = ['foo', 'bar'];
$array2 = [ ...$array1, ...$array1];
// $array2 = ['foo', 'bar', 'foo', 'bar']

Podés desempaquetar una matriz vacía sin errores ni advertencias:

$array1 = [];
$array2 = ['foo', ...$array1];
// $array2 = ['foo']

Podés desempaquetar una matriz que no ha sido almacenada previamente en una propiedad:

$array1 = [...['foo', 'bar'], 'baz'];
// $array1 = ['foo', 'bar', 'baz']

El desempaquetado solo funciona con matrices (u objetos que complementan la interfaz Traversable). Si intentás desempaquetar cualquier otro valor (como nulo), generará un error:

$array1 = null;
$array2 = ['foo', ...$array1]; // PHP Error:  Only arrays and Traversables can be unpacked

Podés desempaquetar el resultado de una función/método:

function getArray() : array
{
    return ['foo', 'bar'];
}

$array = [...getArray(), 'baz'];
// $array = ['foo', 'bar', 'baz']
Matriz asociativa

php-version-81

Desde php 8.1, podés desempaquetar una matriz asociativa (con clave de cadena):

$array1 = ['foo' => 'bar'];
$array2 = [
   'baz' => 'qux',
   ...$array1
];
// $array2 = ['baz' => 'qux', 'foo' => 'bar',]

Podés desempaquetar la matriz con una clave ya existente:

$array1 = ['foo' => 'bar'];
$array2 = [
   'foo' => 'baz',
   ...$array1
];
// $array2 = ['foo' => 'bar',]

Podés desempaquetar una matriz vacía sin error ni advertencia:

$array1 = [];
$array2 = [
   ...$array1,
   ...[]
];
// $array2 = []

Argumentos Nombrados

php-version-80

Desde PHP 8.0, es posible pasar argumentos por nombre en lugar de su posición.

Considerando una función como esta:

function concat(string $first, string $second) : string
{
    return $first . ' ' . $second;
}
$a = concat('foo', 'bar');
// $a = 'foo bar'

Se puede obtener el mismo resultado con la sintaxis del argumento con nombre:

$a = concat(first: 'foo', second: 'bar');
// $a = 'foo bar'

Se puede llamar con argumentos en un orden diferente:

$a = concat(second: 'bar', first: 'foo');
// $a = 'foo bar'

Se pueden omitir parámetros opcionales:

function orGate(bool $option1 = false, bool $option2 = false, bool $option3 = false) : bool
{
   return $option1 || $option2 || $option3;
}
$a = orGate(option3: true);
// $a = true

Pero no podés omitir un argumento obligatorio:

$a = concat(second: 'bar');
// TypeError: concat(): Argument #1 ($first) not passed

Tampoco se pueden incluir argumentos adicionales:

$a = concat(first: 'foo', second: 'bar', third: 'baz');
// PHP Error:  Unknown named parameter $third

Los argumentos con nombre también funcionan con el constructor de objetos:

Class Foo()
{
    public function __construct(
        public string $first,
        public string $second
    ) {}

}
$f = new Foo(first: 'bar', second: 'baz');

Variadics con nombre

Se puede utilizar argumentos con nombre con un parámetro variadic:

function showParams(string ...$params) : array
{
    return $params;
}
$a = showParams(first: 'foo', second: 'bar', third: 'baz');
// $a = ["first" => "foo", "second" => "bar", "third" => "baz"]

Desempaquetando argumentos con nombre

Se puede desempaquetar una matriz asociativa como argumentos con nombre si las claves coinciden con los nombres de los argumentos:

function add(int $a, int $b, int $c) : int
{
    return $a + $b + $c;
}
$array = [
    "b" => 2,
    "c" => 3
];
$r = add(1, ...$array);
// $r = 6

El orden de los elementos en la matriz asociativa no importa:

function add(int $a, int $b, int $c) : int
{
    return $a + $b + $c;
}
$array = [
    "c" => 3,
    "b" => 2,
];
$r = add(1, ...$array);
// $r = 6

Si una clave no coincide con el nombre de un argumento, obtendrás un error:

function add(int $a, int $b, int $c) : int
{
    return $a + $b + $c;
}
$array = [
    "b" => 2,
    "c" => 3,
    "d" => 4,
];
$r = add(1, ...$array); // PHP Error:  Unknown named parameter $d

Recursos adicionales

Funciones flecha

php-version-74

Las funciones flecha son una alternativa a las funciones anónimas usando una sintaxis mas corta. El objetivo principal es reducir la verbosidad cuando sea posible: si solo hay una expresión.

Acá hay un ejemplo de una función simple con una sola expresión:

$foo = function ($bar) {
    return $bar + 1;
}
$a = $foo(1);
// $a = 2

Podés escribir la misma función usando una función flecha:

$foo = fn ($bar) => $bar + 1;
$a = $foo(1);
// $a = 2

No le podés asignar un nombre a una función flecha:

fn foo($bar) => $bar + 1;
// PHP Parse error: Syntax error, unexpected T_STRING, expecting '('

Podés usar una función flecha como un parámetro. Por ejemplo, como un parámetro “invocable” en array_reduce:

$myArray = [10,20,30];

$total = array_reduce($myArray, fn ($carry, $item) => $carry + $item, 0);
// $total = 60

Se permite la sugerencia de tipo como en una función normal:

fn (int $foo): int => $foo;

No es necesario usar return ya que no está permitido:

fn ($foo) => return $foo;
// PHP Parse error: Syntax error, unexpected T_RETURN

Ámbito exterior

La función flecha requiere la palabra clave use para poder acceder a las propiedades desde el ámbito externo:

$bar = 10;
$baz = fn ($foo) => $foo + $bar;
$a = $baz(1);
//$a = 11

La palabra clave use no está permitida:

$bar = 10;
fn ($foo) use ($bar) => $foo + $bar;
// PHP Parse error: Syntax error, unexpected T_USE, expecting T_DOUBLE_ARROW

Podés usar $this como en cualquier otra función:

fn () => $this->foo + 1;

Expresión de coincidencia Match

php-version-80

Desde PHP 8.0, existe una nueva sintaxis match similar a la sintaxis switch. Como cada caso coincidente solo debe contener una expresión, no se puede usar y reemplazar una declaración de cambio en cada situación. Sin embargo, es significativamente más corto y más fácil de leer.

La expresión match siempre devuelve un valor. Cada condición solo permite una sola expresión, e inmediatamente devuelve el valor y no fallará en las siguientes condiciones sin una declaración explícita de break:

$foo = 'baz';
$a = match($foo) {
    'bar' => 1,
    'baz' => 2,
    'qux' => 3,
}
// $a = 2

Lanza una excepción cuando el valor no puede coincidir:

$foo = 'qux';
$a = match($foo) {
    'bar' => 1,
    'baz' => 2,
}
// PHP Error:  Unhandled match value of type string

Pero admite una condición predeterminada:

$foo = 'qux';
$a = match($foo) {
    'bar' => 1,
    'baz' => 2,
    default => 3,
}
// $a = 3

Permite múltiples condiciones en un solo brazo:

$foo = 'bar';
$a = match($foo) {
    'bar', 'baz' => 1,
    default => 2,
}
// $a = 1

Hace una comparación estricta de tipo seguro sin coerción de tipo (es como usar === en lugar de ==):

function showType($param) {
    return match ($param) {
        1 => 'Integer',
        '1' => 'String',
        true => 'Boolean',
    };
}

showType(1); // "Integer"
showType('1'); // "String"
showType(true); // "Boolean"

Recurso externo

Interfaz Stringable

php-version-80

Desde PHP 8.0, hay una nueva interfaz llamada Stringable, que indica que una clase tiene un método mágico __toString(). PHP agrega automáticamente la interfaz Stringable a todas las clases que implementan ese método.

interface Stringable {
    public function __toString(): string;
}

Cuando se define un parámetro con el tipo Stringable, comprobará que la clase dada implementa la interfaz Stringable:

class Foo {
    public function __toString(): string {
        return 'bar';
    }
}

function myFunction(Stringable $param): string {
    return (string) $param;
}
$a = myFunction(new Foo);
// $a = 'bar'

Si una clase dada no implementa __toString(), obtendrá un error:

class Foo {
}

function myFunction(Stringable $param): string {
    return (string) $param;
}
$a = myFunction(new Foo);
// TypeError: myFunction(): Argument #1 ($param) must be of type Stringable, Foo given

Un tipo Stringable no acepta string:

function myFunction(Stringable $param): string {
    return (string) $param;
}
$a = myFunction('foo');
// TypeError: myFunction(): Argument #1 ($param) must be of type Stringable, string given

Por supuesto, para aceptar tanto string como Stringable, puede usar un tipo de unión:

function myFunction(string|Stringable $param): string {
    return (string) $param;
}

Enums

php-version-81

Un Enum (o enumeración) define un nuevo tipo, que tiene un número fijo y limitado de posibles valores.

enum Status
{
    case DRAFT;
    case PUBLISHED;
    case ARCHIVED;
}

En un Enum, cada definición distingue entre mayúsculas y minúsculas. Históricamente, en PHP generalmente representamos “constantes” con mayúsculas para distinguirlas de las variables normales, por lo que tiene sentido apegarse a la notación en mayúsculas para los casos de enumeración. Tené en cuenta que esto funcionará y definirá 3 casos diferentes:

enum MyEnum
{
    case FOO;
    case foo;
    case Foo;
}

Ahora podés comparar fácilmente las enumeraciones con el tipo de operador seguro ===:

$statusA = Status::PENDING;
if ($statusA === Status::PENDING) {
    // true
}

Además, una enumeración se comporta como un objeto PHP tradicional:

$statusA = Status::PENDING;
$statusB = Status::PENDING;
$statusC = Status::ARCHIVED;
$statusA === $statusB; // true
$statusA === $statusC; // false
$statusC instanceof Status; // true

Podés usar Enum para hacer cumplir los tipos:

function myFunction(Status $param)
{
    return $param;
}
$a = myFunction(Status::DRAFT);
// $a = Status::DRAFT
$b = myFunction('foo'); // TypeError: myFunction(): Argument #1 ($param) must be of type Status, string given

Métodos en Enum

Podés definir métodos en un Enum:

enum Status
{
    case DRAFT;
    case PUBLISHED;
    
    public function label(): string
    {
        return match($this) 
        {
            Status::DRAFT => 'Not ready...',   
            Status::PUBLISHED => 'Published !',   
        };
    }
}

Entonces podés usar los métodos en cualquier instancia de enum:

$a = Status::DRAFT;
$a->label(); // 'Not ready...'

Valores de respaldo

A veces es necesario asignar un valor propio a cada caso (ej: para almacenarlo en una base de datos, comparación, etc). Tenés que definir el tipo del valor. Acá hay un ejemplo con un valor definido como un int :

enum HttpStatus: int
{
    case OK = 200;
    case NOT_FOUND = 404;
    case INTERNAL_SERVER_ERROR = 500;
}

Y acá hay un ejemplo de un valor definido como string:

enum Status: string
{
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
}

Recursos externos