---
title: 'PHP 5.5: Generators, finally, password_* API & Migration | DevSense'
description: 'Guía de actualización de PHP 5.5: aprenda sobre generadores eficientes en memoria (yield), bloques try-catch finally, la API nativa de hashing de contraseñas, la sintaxis ClassName::class y cómo migrar tras la depreciación de mysql y preg_replace /e.'
faq:
    - { question: '¿Qué es un Generador en PHP 5.5?', answer: 'Un generador es una función especial que devuelve valores uno a uno bajo demanda utilizando la palabra clave `yield`, lo que permite iterar sobre grandes conjuntos de datos con un consumo mínimo de memoria.' }
    - { question: '¿Cómo mejora la seguridad la nueva API de Hashing de Contraseñas?', answer: 'Proporciona funciones nativas y sencillas (`password_hash` y `password_verify`) que generan automáticamente salts seguros y usan bcrypt por defecto, eliminando las implementaciones caseras y débiles.' }
    - { question: '¿Qué hace ClassName::class?', answer: 'Se resuelve como el nombre completo en formato cadena de la clase (por ejemplo, `App\Models\User`), lo que facilita la refactorización en IDEs y evita errores asociados con escribir los nombres de clases como cadenas manuales.' }
    - { question: '¿Cuál es el papel de Zend OPcache en PHP 5.5?', answer: 'Zend OPcache ahora viene integrado de forma nativa en PHP. Almacena en la memoria compartida el bytecode precompilado de los scripts, acelerando considerablemente los tiempos de ejecución de PHP al evitar la compilación en cada petición.' }
published: '2026-05-31'
---
# PHP 5.5: Eficiencia de Memoria y Seguridad Nativa

Leer un archivo de log de 5 GB línea por línea utilizando `file()` puede agotar la memoria de su servidor en segundos, lanzando el temido error \"Allowed memory size exhausted\". PHP 5.5 resolvió esto para siempre al introducir los generadores (`yield`), permitiendo procesar flujos de datos sobre la marcha de forma amigable con la memoria.

Antes de PHP 5.5, los desarrolladores tenían que procesar grandes archivos o conjuntos de datos construyendo arrays gigantescos en memoria, o escribir objetos Iterator complejos y verbosos. Además, el hash seguro de contraseñas era un caos de salts MD5/SHA256 caseros, y la limpieza de recursos tras los errores era engorrosa porque PHP carecía de un bloque `finally`.

> [!IMPORTANT]
> PHP 5.5 introdujo optimizaciones de memoria revolucionarias a través de generadores y estandarizó la criptografía con la API nativa de hashing de contraseñas (Password Hashing API).

---

## Índice
* [Generadores (`yield`)](#generators)
* [El bloque `finally`](#finally)
* [API Nativa de Hashing de Contraseñas](#password-api)
* [`array_column()` y `::class`](#helpers)
* [Integración de Zend OPcache](#opcache)
* [Errores Comunes](#common-mistakes)
* [Recetas Prácticas](#practical-recipes)
* [Cambios Incompatibles con Versiones Anteriores](#backward-incompatible)
* [🧠 Preguntas de Autoevaluación](#self-check)

---

<a id="generators"></a>
## Generadores (`yield`)

Los generadores calculan los valores sobre la marcha en lugar de construir y devolver un array gigante.

```php
// app/Services/LogReader.php
function readLines(string $filePath): Generator
{
    $handle = fopen($filePath, 'r');
    if (!$handle) {
        return;
    }
    try {
        while (($line = fgets($handle)) !== false) {
            yield trim($line);
        }
    } finally {
        fclose($handle);
    }
}
```

* **Por qué es importante**: Iterar sobre archivos grandes, resultados de bases de datos o secuencias infinitas consume una cantidad de memoria constante y mínima (a menudo menos de unos pocos kilobytes) independientemente del tamaño del conjunto de datos.
* **Consecuencia**: El procesamiento por lotes y las canalizaciones de datos se vuelven sumamente eficientes y estables bajo cargas de trabajo pesadas.

---

<a id="finally"></a>
## El bloque `finally`

PHP 5.5 añade la palabra clave `finally` a la estructura `try-catch`. El código dentro de `finally` se ejecuta independientemente de si se lanzó una excepción o no, incluso si se llama a `return` dentro de `try` o `catch`.

```php
// app/Services/DatabaseClient.php
public function processTransaction()
{
    $this->db->connect();
    try {
        $this->db->execute();
    } catch (\Exception $e) {
        $this->logError($e);
    } finally {
        // Esto se ejecuta SIEMPRE, evitando fugas de recursos
        $this->db->disconnect();
    }
}
```

* **Por qué es importante**: Simplifica las operaciones de limpieza como cerrar punteros de archivos, conexiones a bases de datos o desbloquear archivos.

---

<a id="password-api"></a>
## API Nativa de Hashing de Contraseñas

Deje de generar salts de forma manual. Las nuevas funciones de contraseñas hacen que protegerlas sea infalible.

```php
// app/Services/AuthService.php
// Hashear una contraseña usando bcrypt (PASSWORD_DEFAULT)
$hash = password_hash($password, PASSWORD_DEFAULT);

// Verificar la contraseña en el inicio de sesión
if (password_verify($password, $hash)) {
    // Si el parámetro de costo (cost) o el algoritmo cambia, actualizar el hash
    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $newHash = password_hash($password, PASSWORD_DEFAULT);
        // Guardar $newHash en la base de datos
    }
}
```

> [!NOTE]
> `password_hash` genera un salt criptográfico seguro automáticamente y lo almacena dentro de la propia cadena hash devuelta, lo que significa que no necesita una columna separada en la base de datos para almacenar los salts.

---

<a id="helpers"></a>
## `array_column()` y `::class`

PHP 5.5 introduce dos herramientas sumamente prácticas:

### 1. `array_column()`
Extrae una sola columna de un array multidimensional o de un grupo de objetos.

```php
// app/Services/Report.php
$users = [
    ['id' => 1, 'name' => 'Alice'],
    ['id' => 2, 'name' => 'Bob']
];
$ids = array_column($users, 'id'); // [1, 2]
```

### 2. `ClassName::class`
Devuelve el nombre completo con su espacio de nombres de una clase como una cadena.

```php
// app/Services/Container.php
use App\Models\User;
echo User::class; // "App\Models\User"
```

---

<a id="opcache"></a>
## Integración de Zend OPcache

Zend OPcache ahora está integrado en el núcleo de PHP. Almacena en memoria el bytecode precompilado de PHP, por lo que los archivos no necesitan ser analizados y compilados en cada petición.

* **Por qué es importante**: Aumenta el rendimiento en entornos de producción entre 2 y 3 veces, dependiendo del tamaño del framework.
* **Consecuencia**: Los desarrolladores deben implementar estrategias para vaciar la caché (como llamar a `opcache_reset()` o reiniciar el administrador de procesos) durante el despliegue de la aplicación.

---

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

### 1. Uso del peligroso modificador `/e` en `preg_replace`
El modificador `/e` evalúa la cadena de reemplazo como código PHP, lo que da lugar a vulnerabilidades de ejecución remota de código (RCE). Está depreciado en PHP 5.5.

```php
// app/Helpers/StringHelper.php
// ❌ ¡Depreciado y altamente inseguro!
$output = preg_replace('/(\w+)/e', 'strtoupper("$1")', $text);

// ✅ Enfoque correcto
$output = preg_replace_callback('/(\w+)/', function($m) {
    return strtoupper($m[1]);
}, $text);
```

### 2. No liberar recursos de generadores cuando el bucle termina antes de tiempo
Si sale de un bucle de generador (break), los recursos como archivos abiertos pueden permanecer abiertos a menos que estén envueltos en bloques `try/finally` dentro del generador.

```php
// app/Services/FileReader.php
// ❌ Peligroso: si el bucle se interrumpe, fclose() nunca se ejecuta
function readData($file) {
    $fh = fopen($file, 'r');
    while($line = fgets($fh)) yield $line;
    fclose($fh);
}

// ✅ Enfoque correcto
function readDataSafe($file) {
    $fh = fopen($file, 'r');
    try {
        while($line = fgets($fh)) yield $line;
    } finally {
        fclose($fh); // Se garantiza su ejecución cuando se destruye el generador
    }
}
```

### 3. Confiar en la antigua extensión `mysql`
Las funciones `mysql_connect()` están depreciadas en PHP 5.5.

```php
// app/Database/LegacyDb.php
// ❌ Depreciado en PHP 5.5, lanza un aviso E_DEPRECATED
$conn = mysql_connect('localhost', 'user', 'pass');

// ✅ Enfoque correcto
$conn = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
```

---

<a id="practical-recipes"></a>
## Recetas Prácticas

### Expectativa frente a Realidad: `finally` y Retorno de Valores (Returns)

¿Qué sucede cuando tanto el bloque `try` como el bloque `finally` devuelven valores?

```php
// app/Demo/FinallyDemo.php
function testFinally(): string
{
    try {
        return "Retorno de try";
    } finally {
        return "Retorno de finally";
    }
}

// Expectativa: Devuelve "Retorno de try"
// Realidad:
echo testFinally(); // Salida: Retorno de finally
```

> [!WARNING]
> Si devuelve un valor dentro del bloque `finally`, este sobrescribirá cualquier valor devuelto en los bloques `try` o `catch`. Evite colocar sentencias `return` dentro de `finally`.

---

<a id="backward-incompatible"></a>
## Cambios Incompatibles con Versiones Anteriores

1. **Depreciación del modificador `/e` en `preg_replace`**: Arroja advertencias; debe utilizar `preg_replace_callback()`.
2. **Depreciación de la extensión `mysql`**: Arroja advertencias `E_DEPRECATED` en las conexiones.
3. **`empty()` con expresiones**: Antes de la versión 5.5, `empty()` solo aceptaba variables (por ejemplo, `empty($x)`). Ahora acepta expresiones como `empty(trim($x))`. Aunque no es un cambio que rompa el código directamente, hace que los trucos antiguos queden obsoletos.
4. **Cambios en el formato de `pack()` y `unpack()`**: Ciertos cambios en la alineación de 64 bits podrían afectar la serialización binaria.

---

## 🧠 Preguntas de Autoevaluación

1. **¿Verdadero o Falso?** Una función generadora devuelve un objeto `Generator` que implementa la interfaz `Iterator`.
2. Si se lanza una excepción en un bloque `try` y NO es capturada por ningún bloque `catch`, ¿se sigue ejecutando el código dentro del bloque `finally`?
3. ¿Qué sucede si intenta pasar un array de parámetros de costo directamente a `password_verify()`?
4. **¿Verdadero o Falso?** `ClassName::class` funciona en tiempo de ejecución incluso si la clase no está cargada o no existe.

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

1. **Verdadero.** Los generadores devuelven una instancia de la clase `Generator`, lo que permite utilizarlos directamente dentro de bucles `foreach`.
2. **Sí.** Se garantiza la ejecución del bloque `finally` antes de que la excepción se propague y detenga la ejecución del script.
3. Nada, porque `password_verify` solo acepta dos argumentos: la contraseña en texto plano y el hash. Lee el algoritmo y los parámetros de costo directamente de la propia cadena hash.
4. **Verdadero.** `::class` se resuelve en tiempo de compilación. No intenta realizar una autocarga ni verificar la existencia de la clase; simplemente devuelve la cadena del espacio de nombres.
</details>