¡PHP 8 ya está aquí! Fue lanzado el 26 de noviembre de 2020. Puedes descargarlo aquí. Es una nueva versión principal, lo que significa que introducirá algunos cambios importantes, así como muchas funciones nuevas y mejoras de rendimiento.

Debido a los cambios importantes, existe una mayor probabilidad de que necesite hacer algunos cambios en su código para que se ejecute en PHP 8. Sin embargo, si se ha mantenido actualizado con las últimas versiones, la actualización no debería ser demasiado. difícil, ya que la mayoría de los cambios importantes fueron obsoletos antes en las versiones 7. * Y no se preocupe, todas estas bajas se enumeran en esta publicación.

Además de los cambios importantes, PHP 8 también trae un buen conjunto de nuevas características como el compilador JIT, tipos de unión, atributos y más.

Nuevas características

Union de tipos

Dada la naturaleza tipada dinámicamente de PHP, hay muchos casos en los que los tipos de unión puede ser útil. Los tipos de unión son una colección de dos o más tipos que indican que se puede utilizar cualquiera de ellos.

public function foo(Foo|Bar $input): int|float;

Tenga en cuenta que void nunca puede ser parte de un tipo de unión, ya que indica “ningún valor de retorno”. Además, las uniones que aceptan valores NULL se pueden escribir usando | null, o usando la notación ?:

public function foo(Foo|null $foo): void; 

public function bar(?Bar $bar): void;

JIT

El compilador JIT, justo a tiempo, promete importantes mejoras de rendimiento, aunque no siempre en el contexto de las solicitudes web. He realizado mis propios puntos de referencia en aplicaciones web de la vida real, y parece que el JIT no hace mucha diferencia, si es que hay alguna, en ese tipo de proyectos PHP.

Si desea saber más sobre lo que el JIT puede hacer por PHP, puede leer otra publicación que escribí al respecto aquí.

El operador nullsafe

Si está familiarizado con el operador de fusión nula, ya está familiarizado con sus deficiencias: no funciona en llamadas a métodos. En su lugar, necesita verificaciones intermedias o confiar en ayudantes opcionales proporcionados por algunos marcos:

$fechaInicio = $reservas->getFechaInicio(); 

$fechaString = $fechaInicio ? $fechaInicio->asDateTimeString() : null;

¡Con la adición del operador nullsafe, ahora podemos tener un comportamiento similar a la fusión nula en los métodos!

$fechaString = $reservas->getFechaInicio()?->asDateTimeString();

Puede leer todo sobre el operador nullsafe aquí.

Argumentos nombrados

Los argumentos con nombre le permiten pasar valores a una función, especificando el nombre del valor, para que no tenga que tener en cuenta su orden, ¡y también puede omitir parámetros opcionales!

function foo(string $a, string $b, ?string $c = null, ?string $d = null)  { 
    /* … */ 
} 

foo(
     b: 'value b',
     a: 'value a',
     d: 'value d',
);

Atributos

Los atributos, comúnmente conocidos como anotaciones en otros idiomas, ofrecen una forma de agregar metadatos a las clases, sin tener que analizar docblocks.

En cuanto a un vistazo rápido, aquí hay un ejemplo de cómo se ven los atributos, del RFC:

use App\Attributes\ExampleAttribute; 

#[AtributoEjemplo] 
class Foo {
     #[AtributoEjemplo]
     public const FOO = 'foo';
     
     #[AtributoEjemplo]
     public $x;

     #[AtributoEjemplo]
     public function foo(#[AtributoEjemplo] $bar) { } 
}
#[Attribute] 
class AtributoEjemplo {
     public $value;
     public function __construct($value) {
         $this->value = $value;
     }
}

Tenga en cuenta que este atributo base solía llamarse PhpAttribute en el RFC original, pero luego se cambió por otro RFC. Si desea profundizar en cómo funcionan los atributos y cómo puede crear los suyos propios; puede leer acerca de los atributos en profundidad en este blog.

Expresión de coincidencia

Podría llamarlo el hermano mayor de la expresión de cambio: la coincidencia puede devolver valores, no requiere declaraciones de interrupción, puede combinar condiciones, usa comparaciones de tipos estrictas y no hace ningún tipo de coerción.

Se parece a esto:

$result = match($input) {
     0 => "hello",
     '1', '2', '3' => "world",
 };

Puede leer sobre la expresión de coincidencia en detalle, aquí.

Promoción de parámetros del constructor

Normalmente para inyectar dependencias a una clase lo hacemos a través del constructor así:

class Dinero  {
     public Divisa $divisa;
     public int $cantidad;

     public function __construct(         
         Divisa $divisa,
         int $amount,
     ) {
         $this->divisa = $divisa;
         $this->cantidad = $cantidad;
     }
 }

Bien con el nuevo php 8, todos los argumentos del constructor serán automaticamente declarados e inyectados haciendo esto:

class Dinero  {
     public function __construct(
         public Divisa $divisa,
         public int $cantidad,
     ) {}
 }

Y automagicamente, podremos hacer referencia a los argumentos del constructor como si estuvieran declarados como campos a nivel de clase (ejemplo: $this->divisa).

Tipo de retorno estatico

Si bien ya era posible devolver self, static no era un tipo de retorno válido hasta PHP 8. Dada la naturaleza de tipo dinámico de PHP, es una característica que será útil para muchos desarrolladores.

class Foo
 {
     public function test(): static
     {
         return new static();
     }
 } 

Nuevo tipo mixed

Algunos podrían llamarlo un mal necesario: el tipo mixto hace que muchos tengan sentimientos encontrados. Sin embargo, hay un buen argumento a favor: un tipo faltante puede significar muchas cosas en PHP:

  • Una función no devuelve nada o es nula
  • Esperamos uno de varios tipos
  • Esperamos un tipo que no se puede insinuar en PHP

Debido a las razones anteriores, es bueno que se agregue el tipo mixto. mixed en sí mismo significa uno de estos tipos:

  • array
  • bool
  • callable
  • int
  • float
  • null
  • object
  • resource
  • string

Tenga en cuenta que mixed también se puede utilizar como parámetro o tipo de propiedad, no solo como tipo de retorno.

También tenga en cuenta que dado que mixed ya incluye nulo, no está permitido convertirlo en anulable. Lo siguiente provocará un error:

// Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
 function bar(): ?mixed {}

Expresión throw

Este RFC cambia de ser una declaración a ser una expresión, lo que hace posible lanzar una excepción en muchos lugares nuevos:

$iniciarError = fn () => throw new MyError();

$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');

Herencia con métodos privados

Anteriormente, PHP solía aplicar las mismas comprobaciones de herencia en métodos públicos, protegidos y privados. En otras palabras: los métodos privados deben seguir las mismas reglas de firma de métodos que los métodos protegidos y públicos. Esto no tiene sentido, ya que las clases secundarias no podrán acceder a los métodos privados.

Esta RFC cambió ese comportamiento, por lo que estas comprobaciones de herencia ya no se realizan en métodos privados. Además, el uso de la función privada final tampoco tenía sentido, por lo que al hacerlo ahora se activará una advertencia:

Warning: Private methods cannot be final as they are never overridden by other classes 

Weak maps

Construido sobre el RFC de weakrefs que se agregó en PHP 7.4, se agrega una implementación de WeakMap en PHP 8. WeakMap contiene referencias a objetos, lo que no evita que esos objetos sean recolectados como basura.

Tomemos el ejemplo de los ORM, que a menudo implementan cachés que contienen referencias a clases de entidad para mejorar el rendimiento de las relaciones entre entidades. Estos objetos de entidad no pueden recolectarse como basura, siempre que esta caché tenga una referencia a ellos, incluso si la caché es lo único que hace referencia a ellos.

Si esta capa de almacenamiento en caché usa referencias y mapas débiles en su lugar, PHP recolectará estos objetos cuando ya no haya nada más que haga referencia a ellos. Especialmente en el caso de los ORM, que pueden gestionar varios cientos, si no miles, de entidades dentro de una solicitud; Los mapas débiles pueden ofrecer una forma mejor y más amigable de manejar estos objetos.

Así es como se ven los mapas débiles, un ejemplo del RFC:

class Foo {
     private WeakMap $cache;
  
     public function getAlgoConCache(object $obj): object
     {
         return $this->cache[$obj]
            ??= $this->hacerAlgoComputacionalmenteCaro($obj);
     }
 } 

::clas ahora esta permitido en objetos

Una característica nueva, pequeña pero útil: ahora es posible usar ::class en objetos, en lugar de tener que usar get_class() en ellos. Funciona de la misma forma que get_class().

$foo = new Foo();
var_dump($foo::class); 

Manejo generalizado de errores en sentencias catch

Siempre que quisiera capturar una excepción antes de PHP 8, tenía que almacenarla en una variable, independientemente de si usó esa variable o no. Ahora, puede omitir la variable, así que en lugar de esto:

try {
     //  Algo que puede meter la pata
 } catch (UnaExcepcion $exception) {
     Log::error(“dude, algo metio la pata”);
 } 

Ahora podemos hacer esto:

try {
     //  Algo que puede meter la pata
 } catch (UnaExcepcion) {
     Log::error(“dude, algo metio la pata”);
 } 

Tenga en cuenta que es necesario especificar siempre el tipo, no se le permite tener una captura vacía. Si desea capturar todas las excepciones y errores, puede usar Throwable como el tipo de captura.

Coma final en listas de parámetros

Ya era posible cuando se llamaba a una función, pero aún faltaba el soporte de comas finales en las listas de parámetros. Ahora está permitido en PHP 8, lo que significa que puede hacer lo siguiente:

public function(
     string $parameterA,
     int $parameterB,
     Foo $objectfoo,
 ) {
     // …
 } 

Como nota al margen: las comas finales también se admiten en la lista de uso de cierres, esto fue un descuido y ahora se agregó a través de una RFC separada.

Crear objetos DateTime desde la interfaz

Ya puede crear un objeto DateTime a partir de un objeto DateTimeImmutable usando DateTime::createFromImmutable($ immutableDateTime), pero al revés fue complicado. Al agregar DateTime::createFromInterface() y DatetimeImmutable::createFromInterface() ahora hay una forma generalizada de convertir objetos DateTime y DateTimeImmutable entre sí.

DateTime::createFromInterface(DateTimeInterface $otra);
 
DateTimeImmutable::createFromInterface(DateTimeInterface $otra); 

Nueva interfaz Stringable

La interfaz Stringable se puede usar para escribir sugerencia cualquier cosa que implemente __toString(). Siempre que una clase implementa __toString(), implementa automáticamente la interfaz detrás de escena y no hay necesidad de implementarla manualmente.

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

 function bar(string|Stringable $stringable) { /* … */ }
 

 bar(new Foo());
 bar('abc'); 

Nuevas funciones

Nueva función str_contains()

Algunos podrían decir que está muy atrasada, pero finalmente ya no tenemos que depender de strpos() para saber si una cadena contiene otra cadena.

En lugar de hacer esto:

if (strpos('tres tristes tigres...', 'tigres') !== false) { /* … */ } 

Podemos hacer esto

if (str_contains('tragan trigo en un trigal', 'trigo')) { /* … */ } 

Nuevas funciones str_starts_with() y str_ends_with()

Otras dos que se habían retrasado hace mucho tiempo, estas dos funciones ahora se agregan en el núcleo.

str_starts_with('haystack', 'hay'); // true
str_ends_with('haystack', 'stack'); // true 

Nueva función fdiv()

La nueva función fdiv() hace algo similar a las funciones fmod() e intdiv(), lo que permite la división por 0. En lugar de errores, obtendrá INF, -INF o NAN, según el caso.

Nueva función get_debug_type()

get_debug_type() devuelve el tipo de variable. ¿Suena como algo que haría gettype()? get_debug_type() devuelve resultados más útiles para matrices, cadenas, clases y objetos anónimos.

Por ejemplo, llamar a gettype() en una clase \Foo\Bar devolvería un objeto. El uso de get_debug_type() devolverá el nombre de la clase.

En el RFC se puede encontrar una lista completa de las diferencias entre get_debug_type() y gettype().

Nueva función get_resource_id()

Los recursos son variables especiales en PHP, que se refieren a recursos externos. Un ejemplo es una conexión MySQL, otro un identificador de archivo.

A cada uno de esos recursos se le asigna una identificación, aunque anteriormente la única forma de saber esa identificación era lanzar el recurso a int:

$resourceId = (int) $resource; 

PHP 8 agrega las funciones get_resource_id(), lo que hace que esta operación sea más obvia y segura para los tipos:

$resourceId = get_resource_id($resource); 

Categorized in: