---
title: 'PHP 8.2: What’s New — Types, Readonly Classes, Security & Migration | DevSense'
description: 'Guía de PHP 8.2: clases readonly, tipos independientes null/false/true, tipos DNF, #[SensitiveParameter], extensión Random, depreciación de propiedades dinámicas y cambios incompatibles.'
faq:
    - { question: '¿Qué son las clases Readonly en PHP 8.2?', answer: 'Una clase readonly marca todas sus propiedades como readonly implícitamente. Todas las propiedades deben estar tipadas y la clase no admite propiedades dinámicas. Solo puede heredar de otras clases readonly.' }
    - { question: '¿Cómo mejora #[SensitiveParameter] la seguridad de la aplicación?', answer: 'El atributo #[SensitiveParameter] oculta los valores sensibles (como contraseñas, claves o tokens) en los rastreos de pila (stack traces), evitando su filtración accidental en archivos de registro o salidas de error.' }
    - { question: '¿Qué es DNF (Forma Normal Disyuntiva) en PHP 8.2?', answer: 'DNF permite a los desarrolladores combinar tipos de unión e intersección en un formato estandarizado, como `(Countable&Traversable)|null` para métodos que aceptan estructuras complejas o null.' }
    - { question: '¿Por qué están depreciadas las propiedades dinámicas en PHP 8.2?', answer: 'Las propiedades dinámicas están depreciadas para evitar errores en tiempo de ejecución causados por errores ortográficos en los nombres de las propiedades. Las clases deben declarar sus propiedades, usar `#[AllowDynamicProperties]` o implementar `__set()`/`__get()`.' }
published: '2026-05-31'
---
# PHP 8.2: Características Principales

Notas de campo para equipos que pasan de PHP 8.1.x a 8.2.x: adiciones al lenguaje, atributos orientados a la seguridad, manejo de cadenas más estricto y las depreciaciones que debe limpiar antes del próximo salto.

## Índice
* [#[SensitiveParameter] y rastreos de pila más seguros](#sensitive-parameter)
* [Clases Readonly](#readonly-classes)
* [Tipos independientes (`null`, `false`, `true`) y DNF](#standalone-types-dnf)
* [Constantes en traits y enums en expresiones constantes](#traits-constants)
* [INI: `error_log_mode`](#error-log-mode)
* [Extensión Random](#random-extension)
* [Actualizaciones notables de extensiones (cURL, PCRE)](#extension-updates)
* [Cambios incompatibles con versiones anteriores (notas de migración)](#backward-incompatible)
* [Depreciaciones (corregir antes de que se conviertan en errores)](#deprecations)
* [Notas sobre extensiones y tiempo de ejecución](#extensions-notes)
* [Errores Comunes](#common-mistakes)
* [Quiz de Autoevaluación](#self-test-quiz)

---

PHP 8.2 dirige el lenguaje firmemente hacia la explicitud de tipos y la seguridad estructural. Con la introducción de clases de solo lectura (readonly) y tipos en Forma Normal Disyuntiva (DNF), los desarrolladores obtienen un control granular sobre la inmutabilidad de los objetos y las declaraciones de tipos complejos. La seguridad también se integra a nivel de lenguaje, lo que le permite marcar explícitamente las credenciales usando `#[SensitiveParameter]` para evitar que se filtren en los rastreos de pila. Sin embargo, esta versión introduce depreciaciones significativas—sobre todo, propiedades dinámicas—para detectar errores antes de producción. Aquí tiene su guía de transición a PHP 8.2.

<a id="sensitive-parameter"></a>
## #[SensitiveParameter] y rastreos de pila más seguros

El atributo `#[\SensitiveParameter]` marca los parámetros que deben ocultarse en los rastreos de pila y en las salidas de depuración, lo que reduce la filtración accidental de credenciales en los registros y las páginas de error.

> [!NOTE]
> **¿Sabía que?**
> El atributo `#[SensitiveParameter]` funciona de forma nativa con la salida predeterminada de excepciones de PHP. Cuando PHP genera un rastreo de pila, reemplaza el valor del parámetro con un objeto `SensitiveParameterValue`, ¡enmascarando por completo la cadena original en los registros!

```php
// app/Services/DatabaseService.php
function connect(#[\SensitiveParameter] string $password): void
{
    throw new RuntimeException('fail');
}
```

Combine esto con un registro disciplinado y nunca muestre excepciones crudas en producción.

### Receta práctica: marcar secretos en el límite del sistema

Use `#[\SensitiveParameter]` en parámetros que puedan terminar en excepciones (envoltorios de clientes, asistentes de autenticación). Mantiene útiles los rastreos de pila sin filtrar credenciales.

```php
// app/Clients/ApiClient.php
final class ApiClient
{
    public function __construct(
        private readonly string $baseUrl,
        #[\SensitiveParameter] private readonly string $token,
    ) {}
}
```

---

<a id="readonly-classes"></a>
## Clases Readonly

Una clase se puede declarar `readonly`, haciendo que **todas** sus propiedades de instancia sean readonly y requieran inicialización en el momento de la construcción (similar a aplicar `readonly` a cada propiedad).

> [!NOTE]
> **¿Sabía que?**
> ¡Una clase readonly evita automáticamente las propiedades dinámicas! Ni siquiera necesita usar el atributo `#[AllowDynamicProperties]` porque intentar agregar una propiedad dinámica a una clase readonly lanzará inmediatamente un Error.

```php
// app/DTO/Point.php
readonly class Point
{
    public function __construct(
        public int $x,
        public int $y,
    ) {}
}
```

Use esto para objetos de valor (value objects) inmutables y DTOs donde todo el grafo de objetos deba congelarse después de la construcción.

---

<a id="standalone-types-dnf"></a>
## Tipos independientes (`null`, `false`, `true`) y DNF

PHP 8.2 permite **`null`**, **`false`** y **`true`** como tipos independientes en las declaraciones (no solo como miembros de la unión en formas anteriores).

Los tipos **DNF (Disjunctive Normal Form / Forma Normal Disyuntiva)** le permiten combinar tipos de **unión** e **intersección** en una forma normalizada, por ejemplo, `(A&B)|null`—útil para APIs precisas sin perder la nulabilidad.

```php
// app/Services/ExportService.php
function accepts((Countable&Traversable)|null $c): void {}
```

---

<a id="traits-constants"></a>
## Constantes en traits y enums en expresiones constantes

* **Constantes en traits**: ahora están permitidas—útil para configuraciones compartidas sin una clase base adicional.
* **Propiedades de Enum en expresiones constantes**: puede hacer referencia a casos/propiedades de enum donde se requieran expresiones constantes, lo que permite una configuración más rica en tiempo de compilación.

---

<a id="error-log-mode"></a>
## INI: `error_log_mode`

La directiva INI **`error_log_mode`** establece los permisos de archivo para el archivo de registro de errores cuando PHP lo crea—útil para implementaciones seguras (por ejemplo, evitar registros legibles por todos).

---

<a id="random-extension"></a>
## Extensión Random

La extensión **Random** consolida y amplía las APIs de generación de números aleatorios, con opciones de RNG más claras y menos riesgos que el uso ad hoc de funciones antiguas. Prefiérala para código nuevo que necesite semillas (seeds) reproducibles, mejores algoritmos o capacidad de prueba.

### Receta práctica: `Randomizer` para tokens y muestreo

```php
// app/Services/TokenGenerator.php
$engine = new Random\Engine\Mt19937(random_int());
$randomizer = new Random\Randomizer($engine);
$token = $randomizer->getBytesFromString('0123456789abcdef', 32);
```

Use un motor con semilla en las pruebas para hacer que la salida aleatoria sea determinista; use un motor criptográficamente seguro al generar secretos.

---

<a id="extension-updates"></a>
## Actualizaciones notables de extensiones (cURL, PCRE)

* **cURL**: `CURLINFO_EFFECTIVE_METHOD` expone el método HTTP efectivo; `curl_upkeep()` ayuda con el mantenimiento de la conexión; se exponen constantes de libcurl más nuevas cuando están disponibles.
* **PCRE**: el modificador **`n` (NO_AUTO_CAPTURE)** hace que los grupos ordinarios `()` no capturen a menos que estén nombrados—útil para patrones complejos con menos referencias numeradas.

---

<a id="backward-incompatible"></a>
## Cambios incompatibles con versiones anteriores (notas de migración)

### Fecha y hora

* `DateTime::createFromImmutable()` / `DateTimeImmutable::createFromMutable()` ahora usan tipos de retorno **provisionales `static`** (más estrechos que antes para las herramientas de herencia).
* Formatos de fecha relativa: los símbolos de número ya no permiten signos múltiples (por ejemplo, `+-2`).

### Biblioteca estándar (alto impacto)

* **Mayúsculas y minúsculas ASCII independientes de la configuración regional**: `strtolower()`, `strtoupper()`, `lcfirst()`, `ucfirst()`, `ucwords()` y las llamadas relacionadas **ya no dependen de la configuración regional (locale-sensitive)**; se comportan como la configuración regional `"C"`. Use **mbstring** para el mapeo de mayúsculas y minúsculas localizado.
* **`str_split('')`** ahora devuelve `[]` (anteriormente `[""]`).
* **`glob()` / `GlobIterator`**: bajo `open_basedir`, el comportamiento al devolver array vacío frente a `false` y las advertencias cambiaron—audite el escaneo de directorios en alojamientos restringidos.
* **`FilesystemIterator`**: ya no se fuerza `SKIP_DOTS`; establezca las banderas explícitamente si dependía del comportamiento predeterminado anterior.
* **`ksort` / `krsort`**: `SORT_REGULAR` utiliza las reglas de cadenas numéricas de PHP 8 de forma consistente.
* **`var_export()`**: ya no se omiten las barras invertidas iniciales para los nombres de clase (nombres completamente calificados).

### ODBC / PDO_ODBC

El nombre de usuario y la contraseña se **escapan** cuando se añaden a las cadenas de conexión—corrige inyecciones/cadenas mal formadas; verifique las pruebas de integración contra DSNs reales.

### SPL

Varios métodos de `SplFileObject` ahora imponen firmas; se ajustaron los tipos de retorno para algunos métodos (`hasChildren`, `getChildren`).

---

<a id="deprecations"></a>
## Depreciaciones (corregir antes de que se conviertan en errores)

### Propiedades dinámicas

Crear **propiedades dinámicas** en clases arbitrarias está depreciado a menos que la clase use **`#[\AllowDynamicProperties]`** (o extienda tipos como `stdClass` que lo permitan). Prefiera propiedades declaradas, `WeakMap` para metadatos externos o métodos explícitos `__get`/`__set`.

### Callables parciales

Los callables que solo son aceptados por `call_user_func()` pero no por la forma `$callable()`—por ejemplo, `"self::method"`, `"parent::method"`, ciertas formas de array—están depreciados. Normalice a los patrones `Foo::bar` o `[Class::class, 'method']`.

### Interpolación de cadenas

La interpolación de estilo `"${var}"` / `"${expr}"` está depreciada; use `"{$var}"` o la concatenación explícita.

### Otros

* **`utf8_encode` / `utf8_decode`**: depreciados (use `mb_convert_encoding` o `iconv`).

---

<a id="common-mistakes"></a>
## ⚠️ Errores Comunes

Aquí tiene algunos problemas típicos al usar las características de PHP 8.2:

### 1. Crear Propiedades Dinámicas
En PHP 8.2, asignar un valor a una propiedad no existente en una clase desencadena una advertencia de depreciación, y lanzará un Fatal Error en PHP 9.0.

```php
// app/Services/UserService.php
// MALO: Desencadena una advertencia de depreciación en PHP 8.2
class UserService {
    public string $name;
}

$service = new UserService();
$service->email = 'user@example.com'; // Deprecation Warning: Creation of dynamic property is deprecated
```

### 2. Usar la sintaxis de interpolación de cadenas depreciada
La antigua sintaxis `${var}` está depreciada en PHP 8.2.

```php
// app/Services/NotificationService.php
// MALO: Desencadena una advertencia de depreciación
$name = 'Alice';
echo "Hola ${name}"; // Deprecation Warning

// BUENO: Use la sintaxis de llaves estándar
echo "Hola {$name}";
```

### 3. Intentar hacer que una clase Readonly extienda una clase normal
Una clase `readonly` solo puede extender otra clase `readonly`.

```php
// app/DTO/Point3D.php
class Point2D {}

// MALO: Fatal Error: Readonly class Point3D cannot extend non-readonly class Point2D
readonly class Point3D extends Point2D {}
```

---

<a id="self-test-quiz"></a>
## Quiz de Autoevaluación

Pruebe su comprensión de las características de PHP 8.2.

### Pregunta 1: ¿Qué sucede cuando define una clase como `readonly` en PHP 8.2?
* A) Todas sus propiedades se marcan automáticamente como `readonly`, pero no necesitan estar tipadas.
* B) No puede agregar propiedades dinámicas a la clase y todas las propiedades deben estar tipadas.
* C) Se le permite extender cualquier clase normal, pero las clases normales no pueden extenderla.

<details>
<summary>Mostrar respuestas</summary>

**Respuesta: B**  
Declarar una clase como `readonly` significa que todas sus propiedades son implícitamente readonly y deben estar tipadas. Además, las clases readonly no pueden tener propiedades dinámicas y solo pueden heredar de otras clases readonly.
</details>

### Pregunta 2: ¿Qué sintaxis de interpolación desencadena una advertencia de depreciación en PHP 8.2?
* A) `"Hola {$name}"`
* B) `"Hola ${name}"`
* C) `"Hola " . $name`

<details>
<summary>Mostrar respuestas</summary>

**Respuesta: B**  
El estilo `${var}` de interpolación de cadenas está depreciado en PHP 8.2 y desencadena una advertencia. Debería usar `{$var}` en su lugar.
</details>

---

## Resumen

PHP 8.2 dirige el lenguaje firmemente hacia la explicitud de tipos y la seguridad estructural. Al introducir clases readonly y tipos DNF (Forma Normal Disyuntiva), los desarrolladores obtienen un control granular sobre la inmutabilidad de los objetos y las declaraciones de tipos complejos.