Guía de migración de PHP 7.x a PHP 8.2

Guía de migración de PHP 7.x a PHP 8.2

A partir de la release 9.13.012, Scriptcase pasa a ser compatible con PHP 8.2, tanto en el entorno de desarrollo como en producción.

Al migrar directamente de PHP 7.x a PHP 8.2, los códigos personalizados (eventos, métodos y bibliotecas internas o externas) pueden empezar a emitir warnings, deprecations o incluso presentar fallas, debido a cambios de comportamiento y a la eliminación de recursos introducidos en las versiones más recientes de PHP.

Este tutorial reúne los principales puntos de atención de la migración a PHP 8.2, con explicaciones y ejemplos prácticos para facilitar la adaptación del código y reducir impactos durante la actualización.

1) Operadores ternarios anidados sin paréntesis explícitos — No permitido

Las expresiones condicionales que usan operadores ternarios anidados sin paréntesis explícitos no están permitidas en PHP 8.2.
Este tipo de escritura puede generar ambigüedades y ya no es aceptado por el intérprete.

❌ Ejemplo no permitido:
  1. $result = $aa != "" ? $xxx : isset($bb) && $bb != "" ? $zzz : "";

✅ Forma recomendada:
Reescribe la lógica de forma explícita, usando estructuras condicionales:
  1. if ($aa != "") {
  2.     $result = $xxx;
  3. } elseif (isset($bb) && $bb != "") {
  4.     $result = $zzz;
  5. } else {
  6.     $result = "";
  7. }

2) Acceso a valores de array y string usando llaves — Deprecated

El acceso a valores de arrays y strings usando la sintaxis con llaves {} no está permitido en PHP 8.2.
Este formato está depreciado y puede generar warnings o errores durante la ejecución.

Utiliza siempre la sintaxis con corchetes [] para acceder a índices.

❌ Ejemplo no permitido:
  1. $array = [1, 2];
  2. echo $array{1};
  3. $string = "foo";
  4. echo $string{0};
Quote
Este tipo de acceso genera mensajes como:
Deprecated: Array and string offset access syntax with curly braces is deprecated

✅ Forma correcta:
  1. $array = [1, 2];
  2. echo $array[1]; // muestra 2
  3. $string = "foo";
  4. echo $string[0]; // muestra "f"

3) Parámetros obligatorios después de parámetros opcionales — Deprecated

La declaración de funciones o métodos con parámetros obligatorios después de parámetros opcionales no está permitida en PHP 8.2.
Este tipo de firma se considera incorrecta y puede generar warnings o deprecations durante la ejecución.

❌ Ejemplo no permitido:
  1. function foo($param_optional = null, $param_required) {
  2.     // ...
  3. }
Quote
Este tipo de declaración puede generar mensajes como:
Deprecated: Required parameter $param_required follows optional parameter $param_optional

✅ Forma correcta:
Declara siempre primero los parámetros obligatorios, seguidos por los opcionales:
  1. function foo($param_required, $param_optional = null) {
  2.     // ...
  3. }

4) Operaciones aritméticas con strings no numéricos — No permitido

Las operaciones aritméticas que involucran strings no numéricos no están permitidas en PHP 8.2.
Este tipo de operación puede generar warnings o errores, ya que los valores que no representan números ya no se tratan implícitamente como cero.

❌ Ejemplo no permitido:
  1. $b = "";
  2. $a = $b + 2;
Quote
Este tipo de operación puede provocar un error, ya que $b no contiene un valor numérico válido.

✅ Forma correcta:
Antes de realizar la operación, es necesario garantizar que el valor sea numérico.

Ejemplo 1 — validación directa:
  1. $a = is_numeric($b) ? $b + 2 : 2;

Ejemplo 2 — normalización del valor:
  1. if (!is_numeric($b)) {
  2.     $b = 0;
  3. }
  4. $a = $b + 2;

5) Variables e índices inexistentes — Atención a warnings

El uso de variables no definidas o índices de array inexistentes puede generar warnings en PHP 8.2.
Este comportamiento ocurre cuando el código intenta acceder a valores que aún no han sido definidos.

Si la visualización de warnings está habilitada, este tipo de situación puede generar mensajes frecuentes durante la ejecución del código.

❌ Ejemplo no permitido:
  1. $a = $b + 2;
O:
  1. $a = $array['key'] + 2;
Quote
Cuando $b o $array['key'] no existen, puede mostrarse un warning.

✅ Forma correcta:
Antes de utilizar una variable o un índice de array, verifique si existe.
  1. $a = isset($b) ? $b + 2 : 2;
O, en el caso de arrays:
  1. $a = isset($array['key']) ? $array['key'] + 2 : 2;

6) Función each() — Eliminada


La función each() devuelve el par clave/valor actual de un array y avanza su cursor interno.

Esta función no está disponible en PHP 8.2.
Si se utiliza en sus aplicaciones, el código debe ser modificado antes de publicarse en un entorno con PHP 8.2 o superior.

Opciones comunes de sustitución:
  1. foreach()
  2. key()
  3. current()
  4. next()

❌ Ejemplo no soportado:
  1. $result = "";

  2. $tab = array(
  3.     0 => array('tp' => 1, 'vl' => 'aaa'),
  4.     1 => array('tp' => 2, 'vl' => 'bbb'),
  5.     2 => array('tp' => 3, 'vl' => 'ccc')
  6. );

  7. while (list($key, $val) = each($tab)) {
  8.     $result .= $tab[$key]["vl"];
  9. }

✅ Forma recomendada (usando foreach()):
  1. $result = "";

  2. $tab = array(
  3.     0 => array('tp' => 1, 'vl' => 'aaa'),
  4.     1 => array('tp' => 2, 'vl' => 'bbb'),
  5.     2 => array('tp' => 3, 'vl' => 'ccc')
  6. );

  7. foreach ($tab as $key => $val) {
  8.     $result .= $tab[$key]["vl"];
  9. }

7) Función array_key_exists() — Uso en objetos deprecated

La función array_key_exists() verifica si una clave o índice existe en un array.
En PHP 8.2, el uso de esta función para verificar propiedades de objetos está marcado como deprecated.

Para este escenario, utilice isset() o property_exists().

❌ Ejemplo no recomendado:
  1. if (array_key_exists('index', $array1)) {
  2.     // código
  3. }
✅ Forma recomendada:
  1. if (isset($array1['index'])) {
  2.     // código
  3. }

8) Función money_format() — Eliminada

La función money_format() formatea un número como una cadena de moneda.

Esta función no está disponible en PHP 8.2.
Para realizar el formato monetario, utilice la extensión Intl mediante la clase NumberFormatter.

❌ Ejemplo no soportado:
  1. echo money_format("%.2n", 1234.56);
✅ Forma recomendada (usando NumberFormatter):
  1. $currencyObject = new NumberFormatter("es-ES", NumberFormatter::CURRENCY);
  2. echo $currencyObject->format(1234.56);

9) Función mb_strrpos() — Parámetro de encoding deprecated

La función mb_strrpos() localiza la última ocurrencia de un valor dentro de una cadena.

En PHP 8.2, pasar la codificación como tercer parámetro está marcado como deprecated.
En su lugar, pase un offset como tercer parámetro y la codificación como cuarto.

❌ Ejemplo no recomendado:
  1. $string = 'El ratón roió la ropa';
  2. echo mb_strrpos($string, 'roió', 'UTF-8');
✅ Forma correcta:
  1. $string = 'El ratón roió la ropa';
  2. echo mb_strrpos($string, 'roió', 0, 'UTF-8');

10) Propiedades dinámicas (dynamic properties) — Deprecated

En PHP 8.2, crear propiedades que no existen en la clase directamente en un objeto (por ejemplo, obj->nueva = 1;) pasa a generar una advertencia de deprecation.
Este comportamiento solo está permitido cuando la propia clase autoriza la creación dinámica de propiedades o cuando el objeto es del tipo stdClass.

Antes (sin aviso):
Era posible crear propiedades dinámicamente en objetos sin que PHP emitiera ningún aviso.
  1. class User {} $u = new User();
  2. $u->name = "Ana"; // propiedad dinámica
PHP 8.2 (genera deprecation):
Este tipo de uso pasa a generar una advertencia de deprecation. Para evitar el aviso, puede:
  1. Declarar la propiedad directamente en la clase;
  2. Usar el atributo #[\AllowDynamicProperties] (solución paliativa);
  3. Utilizar WeakMap cuando no se tiene control sobre la clase.

11) “Relative callables” — Deprecated

Algunos formatos de callable que funcionaban con call_user_func(), pero no funcionan correctamente cuando se ejecutan como $callable(), pasaron a estar marcados como deprecated en PHP 8.2.
Esto incluye llamadas que dependen del contexto de la clase, como "self::method", "parent::method", "static::method" y ["self", "method"].

❌ Evite usar:
  1. call_user_func("self::doStuff");
  2. call_user_func(["self", "doStuff"]);
✅ Use en su lugar:
El nombre completo de la clase:
  1. call_user_func("MiClase::doStuff");
  2. call_user_func(["MiClase", "doStuff"]);
O una closure, cuando sea necesario acceder al contexto actual:
  1. call_user_func(fn() => $this->doStuff());

12) Interpolación "${var}" y "${expr}" en strings — Deprecated

En PHP 8.2, el uso de interpolación en el formato "${var}" y "${expr}" dentro de cadenas pasó a estar marcado como deprecated, ya que este estilo es menos claro y puede generar ambigüedades.

❌ Evite:
  1. echo "Hola ${name}";
  2. echo "Total: ${arr['total']}";
✅ Use:
  1. echo "Hola $name";
  2. echo "Hola {$name}";
  3. echo "Total: {${arr['total']}}"; // para expresiones

13) utf8_encode() y utf8_decode() — Deprecated

Las funciones utf8_encode() y utf8_decode() fueron marcadas como deprecated en PHP 8.2, ya que asumen una codificación fija, lo que puede generar resultados incorrectos en distintos escenarios.

Sustituciones comunes:
  1. mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1') // ajuste la codificación de origen según el caso
  2. iconv('ISO-8859-1', 'UTF-8//TRANSLIT', $str) // cuando sea aplicable
Quote
Estas funciones asumen la codificación ISO-8859-1 por defecto, lo que puede causar confusión y conversiones incorrectas; por ello fueron descontinuadas.

14) Funciones “case-insensitive” y conversión de mayúsculas/minúsculas — Cambio de comportamiento

En PHP 8.2, varias funciones que convierten o comparan texto ignorando mayúsculas y minúsculas pasaron a utilizar reglas ASCII (locale por defecto “C”).
Esto incluye funciones como strtolower(), strtoupper(), ucwords() y str_ireplace().

Con este cambio, estas funciones ya no consideran reglas específicas de idioma, lo que puede afectar textos con acentos o idiomas con reglas propias de capitalización, como portugués (pt-BR) y turco (tr-TR).

Para trabajar correctamente con textos localizados o caracteres acentuados, utilice la extensión MBString, por ejemplo:
  1. mb_strtolower($texto, 'UTF-8');

15) glob() con open_basedir — Cambio en el retorno

En PHP 8.2, el comportamiento de la función glob() cambió cuando la directiva open_basedir está activa.
  1. Si todas las rutas están bloqueadas por open_basedir, glob() devuelve un array vacío ([]) — antes devolvía false.
  2. Si solo algunas rutas están bloqueadas, puede mostrarse un warning.
Código que puede verse afectado:
  1. $files = glob($pattern);
  2. if ($files === false) {
  3.     // ...
  4. }
Ajuste recomendado:
Actualice la verificación para considerar también el retorno [], asegurando que el código maneje correctamente ambos escenarios.

Corrección (manejar false y []):
  1. $files = glob($pattern);
  2. if ($files === false || $files === []) {
  3.     // Ningún archivo encontrado O acceso bloqueado por open_basedir
  4.     // maneje aquí (fallback, log, etc.)
  5. } else {
  6.     foreach ($files as $file) {
  7.         // procesa los archivos
  8.     }
  9. }
Alternativa más corta (cuando no es necesario diferenciar false de []):
  1. $files = glob($pattern);
  2. if (empty($files)) {
  3.     // vacío ([]) o false
  4. } else {
  5.     foreach ($files as $file) {
  6.         // ...
  7.     }
  8. }

16) Otros comportamientos que pueden generar “efectos secundarios” (menos comunes)

En PHP 8.2, algunos cambios menores pueden causar diferencias en los resultados de códigos que dependen exactamente del valor retornado o del orden de los datos.

str_split("") ahora devuelve []

Esto puede afectar validaciones que esperan siempre al menos un elemento en el array.
  1. var_dump(str_split(""));
  2. // PHP 8.2: array(0) { }
  3. // Antes: array(1) { [0] => string(0) "" }

var_export() y nombres de clases totalmente calificados

La función var_export() pasó a exportar los nombres de las clases utilizando el nombre totalmente calificado (incluyendo \), especialmente cuando la clase se encuentra dentro de un namespace.
Esto puede generar diferencias en pruebas automatizadas, snapshots o comparaciones de string.
  1. namespace App\Model;
  2. class User {}
  3. echo var_export(new User(), true);
  4. // PHP 8.2: \App\Model\User::__set_state(array(
  5. // ...
  6. // ))

ksort() / krsort() con SORT_REGULAR y strings numéricas

En algunos casos, el orden de los elementos puede cambiar cuando las claves del array son strings numéricas, por ejemplo "2" y "10".

  1. $a = ["10" => "diez", "2" => "dos", "1" => "uno"];
  2. ksort($a, SORT_REGULAR);
  3. var_dump(array_keys($a));
  4. krsort($a, SORT_REGULAR);
  5. var_dump(array_keys($a));
    • Related Articles

    • Cómo Generar el Informe para la Migración de PHP

      Con el objetivo de ayudar a los clientes que utilizan Scriptcase con una versión desactualizada de PHP (7.0 o 7.3), hemos preparado una guía para facilitar la migración de proyectos. Para ayudar con la migración, es necesario enviar un informe que ...
    • Actualizando el PHP de Scriptcase

      Actualmente, la instalación de Scriptcase 9.x viene con la versión 7.0.14 de PHP, desafortunadamente esta versión tiene un problema de compatibilidad con la nueva versión de autenticación de MySQL 8.0, por lo que es necesario realizar la ...
    • Setting environment manually PHP 5.4 - Mac OS X

      We must follow the steps below to perform the installation of php 5.4 on Mac OS X (Mavericks) Run in terminal: sudo curl -s http://php-osx.liip.ch/install.sh | bash -s 5.4 Installation path: /usr/local/php5 Run in the terminal: sudo nano ...
    • Setting environment manually PHP 5.6 - Mac OS X

      We must follow the steps below to perform the installation of php 5.6 on Mac OS X (Mavericks) Run in terminal: sudo curl -s http://php-osx.liip.ch/install.sh | bash -s 5.6 Installation path: /usr/local/php5 Run in the terminal: sudo nano ...
    • Instalando PHP 7.3 - macOS

      Esta documentación contiene información sobre los pasos necesarios para la instalación de PHP 7.3 y Scriptcase de forma manual en entornos macOS. Realizando este tipo de instalación, usted es responsable de configurar todo su entorno, así como las ...