compact y extract en PHP: convertir entre arrays y variables

compact() crea un array asociativo a partir de variables del scope actual, usando el nombre de la variable como clave. extract() hace exactamente lo contrario: a partir de un array asociativo, crea variables locales con el nombre de cada clave. Son útiles en plantillas o vistas, pero extract() tiene una reputación bien ganada de ser peligrosa cuando los datos vienen de fuentes no confiables.

compact(): de variables a array

<?php
$nombre   = 'Ana García';
$email    = '[email protected]';
$rol      = 'editora';
$activa   = true;

// Sin compact: verboso
$usuario = [
    'nombre' => $nombre,
    'email'  => $email,
    'rol'    => $rol,
    'activa' => $activa,
];

// Con compact: más conciso
$usuario = compact('nombre', 'email', 'rol', 'activa');

print_r($usuario);
// Array ( [nombre] => Ana García [email] => [email protected] [rol] => editora [activa] => 1 )
?>

Uso habitual en plantillas y controladores

<?php
function renderVista(string $plantilla, array $datos): void
{
    extract($datos, EXTR_SKIP); // solo crea variables si no existen ya
    include __DIR__ . "/vistas/{$plantilla}.php";
}

// En el controlador
$titulo     = 'Lista de productos';
$productos  = obtenerProductos();
$paginacion = calcularPagina($_GET['p'] ?? 1, count($productos));

renderVista('productos/lista', compact('titulo', 'productos', 'paginacion'));
?>

extract(): de array a variables

<?php
$config = [
    'host'     => 'localhost',
    'puerto'   => 3306,
    'database' => 'tienda',
    'charset'  => 'utf8mb4',
];

extract($config);

// Ahora existen las variables $host, $puerto, $database, $charset
echo $host;     // localhost
echo $puerto;   // 3306
echo $database; // tienda
?>

Los flags: EXTR_SKIP, EXTR_PREFIX_ALL y EXTR_OVERWRITE

<?php
$nombre = 'Variable original'; // ya existe

$datos = ['nombre' => 'Del array', 'edad' => 28];

// EXTR_OVERWRITE (por defecto): sobreescribe variables existentes
extract($datos, EXTR_OVERWRITE);
echo $nombre; // "Del array" ? sobreescribió la original

// Resetear
$nombre = 'Variable original';

// EXTR_SKIP: no sobreescribe si ya existe
extract($datos, EXTR_SKIP);
echo $nombre; // "Variable original" ? preservada

// EXTR_PREFIX_ALL: añade prefijo a todas las claves
extract($datos, EXTR_PREFIX_ALL, 'arr');
echo $arr_nombre; // "Del array"
echo $arr_edad;   // 28
?>

Por qué extract() con $_POST es peligroso

<?php
// NUNCA hagas esto
extract($_POST); // ? vulnerabilidad crítica

// Si el formulario envía ?admin=1 o ?isLoggedIn=true,
// esas variables se crean en el scope actual, pudiendo
// sobreescribir variables de control de acceso:
$esAdmin = false;
extract($_POST); // si POST trae 'esAdmin=1', ahora $esAdmin es '1'

if ($esAdmin) { // BYPASS del control de acceso
    // acceso concedido incorrectamente
}
?>

El destructuring como alternativa segura

En PHP 7.1+ el destructuring de arrays es más explícito y legible que extract() cuando sabes exactamente qué campos esperas:

<?php
$datos = ['nombre' => 'Ana', 'edad' => 28, 'ciudad' => 'Madrid'];

// Destructuring: solo extraes lo que declaras explícitamente
['nombre' => $nombre, 'edad' => $edad] = $datos;

echo $nombre; // Ana
echo $edad;   // 28
// $ciudad no se extrae, sin riesgo de contaminación del scope
?>

La documentación oficial de compact() y la de extract() detallan todos los flags disponibles y las advertencias de seguridad sobre el uso con datos de entrada del usuario.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP