PHP 8.3 se publicó según lo previsto el 23 de noviembre y contiene muchas nuevas funciones y mejoras desde el lanzamiento de PHP 8.2. Aunque oficialmente se considera una versión menor, algunos de los cambios de la 8.3 podrían afectar directamente a tu trabajo con PHP, quizás ayudándote a programar más rápido y con menos errores.
Echemos un vistazo a los grandes — y a veces no tan grandes — cambios de esta última versión.
Nuevas Funciones y Mejoras en PHP 8.3
Empecemos explorando las características de PHP 8.3 que acaparan la mayoría de los titulares.
Constantes de Clase Tipadas
La posibilidad de declarar tipos para las propiedades de las clases está disponible desde PHP 7.4. Sin embargo, a pesar de los numerosos ajustes en la tipificación de PHP a lo largo de los años, no se ha extendido a las constantes — hasta ahora.
Las constantes de clase — y eso incluye también las constantes de interfaz, traits y enum — se pueden tipar en PHP 8.3, lo que hace menos probable que los desarrolladores se desvíen de la intención que hay detrás de la declaración inicial de una constante.
Aquí hay un ejemplo básico utilizando una interfaz:
// Legal:
interface ConstTest {
// Declared type and value are both strings
const string VERSION = "PHP 8.3";
}
// Illegal:
interface ConstTest {
// Type and value mismatch in this initial declaration
const float VERSION = "PHP 8.3";
}
El valor real de esas constantes de clase tipadas se revela cuando se trabaja en clases derivadas de las declaraciones base. Aunque una clase derivada puede asignar con frecuencia un nuevo valor a una constante, PHP 8.3 puede ayudar a evitar que se cambie accidentalmente su tipo de modo que resulte incompatible con la declaración inicial:
class ConstTest {
const string VERSION = "PHP 8.2";
}
class MyConstTest extends ConstTest {
// Legal:
// It's OK to change the value of VERSION here
const string VERSION = "PHP 8.3";
// Illegal:
// Type must be declared if it was specified in the base class
const VERSION = "PHP 8.3";
// Illegal:
// In this case, we can't change the type declared in the
// base class, even if the new type and its value are compatible.
const float VERSION = 8.3;
}
Ten en cuenta que el tipo asignado a una constante de clase puede variar cuando se «estrechan» varios tipos o se utiliza un tipo por lo demás compatible:
class ConstTest {
const string|float VERSION = "PHP 8.2";
}
class MyConstTest extends ConstTest {
// Legal:
// Here, it's OK to narrow the type declaration to string or float
const string VERSION = "PHP 8.3";
const float VERSION = 8.3;
// Legal:
// Value could be an int, but it's compatible with float
const float VERSION = 8;
// Illegal:
// We can't widen the type options here to include int
const string|float|int VERSION = 8;
}
Dos tipos admitidos para otras propiedades al validar valores de retorno – void
y never
– no se admiten como tipos de constante de clase.
Una Nueva Función json_validate()
Cuando se trabaja con datos codificados en JSON, es bueno saber si la carga útil es sintácticamente válida antes de intentar hacer algo con ella.
En versiones anteriores de PHP, los desarrolladores han utilizado la función json_decode()
y han comprobado si había errores mientras esa función intentaba convertir los datos JSON en arrays asociativas u objetos. La nueva función json_validate()
realiza la comprobación de errores sin utilizar toda la memoria necesaria para construir esas estructuras de arrays u objetos.
Así que, en el pasado, en el pasado, podrías haber validado una carga útil JSON similar a ésta:
$obj = json_decode($maybeJSON);
if (json_last_error() === JSON_ERROR_NONE) {
// Probably do something with $obj
}
Si no vas a hacer algo inmediatamente con $obj
en el ejemplo anterior, eso son muchos recursos utilizados sólo para confirmar la validez de la carga útil JSON original. En PHP 8.3, puedes hacer algo como esto y ahorrar algo de memoria:
if (json_validate($maybeJSON)) {
// Do something with $maybeJSON
}
Nota: De todos modos, no tiene mucho sentido utilizar json_validate()
y luego pasar inmediatamente los datos por json_decode()
, utilizando los recursos de memoria de la descodificación. Es más probable que utilices la nueva función para validar el JSON antes de almacenarlo en algún sitio o entregarlo como respuesta a una solicitud.
Clonación Profunda de Propiedades readonly
La capacidad de declarar propiedades de clase individuales como readonly
apareció en PHP 8.1. PHP 8.2 introdujo la posibilidad de asignar ese atributo a toda una clase. Sin embargo, muchos desarrolladores consideraban que las restricciones impuestas al trabajar con clases que contenían dichas propiedades obstaculizaban una programación útil.
Una RFC para modificar el comportamiento de readonly
hizo dos propuestas:
- Permitir que las clases que no son
readonly
extiendan a las clases que sí lo son - Permitir que las propiedades de
readonly
se reinicien al clonar
Es la segunda propuesta la que ha llegado a PHP 8.3. El nuevo enfoque permite que las instancias de una clase con propiedades readonly
se reinicien dentro del método mágico __clone
(incluso a través de funciones invocadas desde dentro de __clone
).
Este ejemplo de código de la RFC muestra cómo funciona:
class Foo {
public function __construct(
public readonly DateTime $bar,
public readonly DateTime $baz
) {}
public function __clone() {
// $bar will get a new DateTime when clone is invoked
$this->bar = clone $this->bar;
// And this function will be called
$this->cloneBaz();
}
private function cloneBaz() {
// This is legal when called from within __clone
unset($this->baz);
}
}
$foo = new Foo(new DateTime(), new DateTime());
$foo2 = clone $foo;
Nuevo Atributo #[\Override]
Al implementar interfaces en PHP, los programadores proporcionan funcionalidad detallada para los métodos nombrados en esas interfaces. Al crear una instancia de una clase, los programadores pueden anular un método padre creando una versión alternativa con el mismo nombre y una firma compatible en el hijo.
Uno de los problemas es que los programadores pueden pensar que están implementando un método de la interfaz o anulando un método padre, cuando no es así. Podrían estar creando una bestia completamente distinta debido a un error tipográfico en el nombre del método de la clase hija o porque se han eliminado o renombrado métodos en el código padre.
PHP 8.3 introduce el atributo #[\Override]
para ayudar a los programadores a dejar claro que un método debe tener algún linaje dentro del código.
Aquí hay un ejemplo básico:
class A {
protected function ovrTest(): void {}
}
// This will work because ovrTest()
// can be found in the parent class
class B extends A {
#[\Override]
public function ovrTest(): void {}
}
// This will fail because ovrBest()
// (probably a typo) is not in the parent
class C extends A {
#[\Override]
public function ovrBest(): void {}
}
Obtención Dinámica de Constantes de Clase y Miembros de Enum
A diferencia de lo que ocurre con otras propiedades en el código PHP, la obtención de constantes de clase y miembros de Enum con nombres de variables ha sido un poco enrevesada. Antes de PHP 8.3, puede que lo hicieras utilizando la función constant()
de esta forma:
class MyClass {
public const THE_CONST = 9;
}
enum MyEnum int {
case FirstMember = 9;
case SecondMember = 9;
}
$constantName = 'THE_CONST';
$memberName = 'FirstMember';
echo constant('MyClass::' . $constantName);
echo constant('MyEnum::' . $memberName)->value;
Ahora, utilizando las mismas definiciones de clase y Enum anteriores, puedes conseguir el mismo resultado con la obtención dinámica de constantes de PHP 8.3 de esta forma:
$constantName = 'THE_CONST';
$memberName = 'FirstMember';
echo MyClass::{$constantName};
echo MyEnum::{$memberName}->value;
Nuevo Método getBytesFromString()
¿Alguna vez has querido generar cadenas aleatorias utilizando una colección preaprobada de caracteres? Ahora puedes hacerlo fácilmente con el método getBytesFromString()
que se ha añadido a la extensión Random en PHP 8.3.
Este nuevo método es sencillo: le pasas una cadena de caracteres como material de origen y especificas cuántos de ellos quieres utilizar. A continuación, el método seleccionará bytes de la cadena de forma aleatoria hasta que alcance esa longitud especificada.
Aquí tienes un ejemplo sencillo:
$rando = new Random\Randomizer();
$alpha = 'ABCDEFGHJKMNPQRSTVWXYZ';
$rando->getBytesFromString($alpha, 6); // "MBXGWL"
$rando->getBytesFromString($alpha, 6); // "LESPMG"
$rando->getBytesFromString($alpha, 6); // "NVHWXC"
Es posible que la longitud solicitada de la salida aleatoria tenga más bytes que la cadena de entrada:
$rando = new Random\Randomizer();
$nums = '123456';
$rando->getBytesFromString($nums, 10); // "2526341615"
Con una cadena de entrada de caracteres únicos, cada uno tiene la misma probabilidad de ser seleccionado para el resultado aleatorio. Sin embargo, los caracteres se pueden ponderar haciendo que aparezcan más a menudo que otros en la entrada. Por ejemplo:
$rando = new Random\Randomizer();
$weighted = 'AAAAA12345';
$rando->getBytesFromString($weighted, 5); // "1AA53"
$rando->getBytesFromString($weighted, 10); // "42A5A1AA3A"
Nuevos Métodos getFloat()
y nextFloat()
Ampliando también la extensión Random, PHP 8.3 introduce dos nuevos métodos para generar valores flotantes aleatorios: getFloat()
y nextFloat()
.
Aquí hay un ejemplo:
$rando = new Random\Randomizer();
// Generate a float value between a minimum
// value of 0 and a maximum value of 5
$rando->getFloat(0,5); // 2.3937446906217
El método getFloat()
también acepta un tercer parámetro después de los valores mínimo y máximo. Utilizando un Enum Random\IntervalBoundary puedes determinar si los propios valores mínimo y máximo pueden ser devueltos por la función.
Éstas son las reglas:
- IntervalBoundary::ClosedOpen: puede devolverse el mínimo, pero no el máximo
- IntervalBoundary::ClosedClosed: se pueden devolver tanto el mín. como el máx
- IntervalBoundary::OpenClosed: no puede devolverse el mínimo, pero sí el máximo
- IntervalBoundary::OpenOpen: no puede devolverse ni el mínimo ni el máximo
Cuando se utiliza getFloat()
sin especificar el Enum como tercer parámetro, el valor por defecto es IntervalBoundary::ClosedOpen.
Un ejemplo útil proporcionado por la documentación de la nueva función genera coordenadas aleatorias de longitud y latitud, donde las latitudes pueden incluir -90 y 90, pero la longitud no puede incluir -180 y 180 (ya que son iguales):
$rando = new Random\Randomizer();
printf(
"Lat: %+.6f Long: %+.6f",
$rando->getFloat(-90, 90, \Random\IntervalBoundary::ClosedClosed),
// -180 will not be used
$rando->getFloat(-180, 180, \Random\IntervalBoundary::OpenClosed),
);
El nuevo método nextFloat()
es esencialmente lo mismo que utilizar getFloat()
para solicitar un valor aleatorio que vaya de 0 a menos de 1:
$rando = new Random\Randomizer();
$rando->nextFloat(); // 0.3767414902847
Otros Cambios Menores en PHP 8.3
PHP 8.3 también incluye otras funciones nuevas y cambios menores. Los mencionaremos a continuación con enlaces a recursos adicionales (cuando estén disponibles):
- Nuevos métodos para la clase DOMElement:
DOMElement::getAttributeNames()
,DOMElement::insertAdjacentElement()
,DOMElement::insertAdjacentText()
,DOMElement::toggleAttribute()
,DOMNode::contains()
,DOMNode::getRootNode()
,DOMNode::isEqualNode()
dOMNameSpaceNode::contains(), yMParentNode::replaceChildren()
. - Nuevos métodos para la clase IntlCalendar:
IntlCalendar::setDate()
,IntlCalendar::setDateTime()
,IntlGregorianCalendar::createFromDate()
yIntlGregorianCalendar::createFromDateTime()
. - Nuevas funciones LDAP: ldap_connect_wallet() y ldap_exop_sync().
- Nuevo
mb_str_pad()
función cadena multibyte. - Nuevas funciones POSIX:
posix_sysconf()
,posix_pathconf()
,posix_fpathconf()
yposix_eaccess()
. - Nuevo método
ReflectionMethod::createFromMethodName()
método. - Nueva función de socket:
socket_atmark()
. - Nuevas funciones de cadena:
str_increment()
,str_decrement()
ystream_context_set_options()
. - Nuevo método de la clase ZipArchive:
ZipArchive::getArchiveFlag()
. - Nuevo ajuste INI para establecer el tamaño máximo de stack permitido:
zend.max_allowed_stack_size
.
Depreciaciones en PHP 8.3
Con cada nueva versión de PHP, algunas funciones y configuraciones se marcan para su eventual eliminación. Una vez desaprobadas, estas funciones no se recomiendan para un uso continuado y generarán avisos en muchos registros cuando aparezcan en código en ejecución.
Aquí tienes una lista de desaprobaciones en PHP 8.3, con enlaces a información adicional:
- La constante U_MULTIPLE_DECIMAL_SEPERATORS queda obsoleta en favor de U_MULTIPLE_DECIMAL_SEPARATORS.
- La variante
3MT_RAND_PHP
Mt19937 está obsoleta. ReflectionClass::getStaticProperties()
ya no es anulable.- Ajustes INI
assert.active
,assert.bail
,assert.callback
,assert.exception
yassert.warning
están obsoletos. - Llamando a
get_class()
yget_parent_class()
sin argumentos están obsoletos.
Resumen
Hemos visto los cambios significativos incluidos en PHP 8.3. Para obtener una lista detallada de todas las actualizaciones de esta versión, puedes consultar el registro oficial de cambios de la versión. Si planeas trasladar tu código a una plataforma que ejecute la última versión de PHP, la Guía de Migración de 8.2 a 8.3 puede ayudarte a no tener problemas.
Si te corresponde instalar PHP en tus servidores de desarrollo o producción, la versión 8.3 ya está lista para su descarga.
Si eres cliente de Kinsta, puedes confiar en nosotros para que esta versión esté disponible en los servidores de tus proyectos de Alojamiento Administrado de WordPress o Alojamiento de Aplicaciones.
Deja una respuesta