Copia profunda de arrays en PHP: mitos y realidad
\n\nImagina la situación: estás escribiendo un script que procesa datos de una base de datos. Obtienes un array de usuarios, haces algo con él, y de repente descubres que los datos originales han cambiado. ¿Te suena? Si trabajas con PHP, este problema puede sorprender incluso a un desarrollador experimentado.
\n\nLa pregunta «Is there a function to make a copy of a PHP array to another?» en Stack Overflow ha acumulado decenas de miles de visitas. Y no es casualidad. A primera vista, parece que copiar arrays en PHP es una tarea trivial. Pero el diablo, como siempre, está en los detalles.
\n\nEn este artículo, analizaremos todas las formas posibles de copiar un array en PHP: desde la asignación simple hasta el trabajo con estructuras multidimensionales. Aprenderás cuándo PHP crea una copia real y cuándo solo una referencia a los datos. ¡Vamos allá!
\n\nAsignación directa: la primera sorpresa
\n\nLa forma más intuitiva es simplemente asignar el array a otra variable:
\n\n$original = ['apple', 'banana', 'cherry'];\n$copy = $original;\n$copy[0] = 'mango';\n\nprint_r($original);\n// Array ( [0] => apple [1] => banana [2] => cherry )\nprint_r($copy);\n// Array ( [0] => mango [1] => banana [2] => cherry )\n\n¡Sorprendentemente, funciona! En PHP, los arrays son value types (tipos de valor), no tipos de referencia. Cuando asignas un array a otra variable, PHP crea una copia superficial (shallow copy) con copia diferida (copy-on-write).
\n\nEn palabras simples: mientras no modifiques ninguno de los arrays, ambos apuntan a los mismos datos en memoria. En cuanto intentas cambiar un elemento en una de las variables, PHP asigna nueva memoria y copia los datos. Esto es muy eficiente y no requiere acciones adicionales.
\n\nConclusión: para arrays unidimensionales simples, la asignación directa es una copia completa.
\n\nTrampa: objetos dentro del array
\n\nAhora imagina que dentro del array hay objetos:
\n\nclass User {\n public $name;\n public function __construct($name) {\n $this->name = $name;\n }\n}\n\n$original = [new User('Alice'), new User('Bob')];\n$copy = $original;\n$copy[0]->name = 'Charlie';\n\nprint_r($original[0]->name); // Charlie\n\n¡Ahí está la sorpresa! La copia superficial copió la referencia al objeto, no el objeto en sí. Al modificar el objeto en la copia, también lo modificas en el original. Para los objetos se necesita otro enfoque.
\n\nFunción array_merge(): matices no evidentes
\n\nA menudo se recomienda usar array_merge() para copiar un array:
$original = [1, 2, 3];\n$copy = array_merge([], $original);\n$copy[0] = 100;\n\nprint_r($original); // [1, 2, 3]\n\nSí, funciona. Pero hay un matiz importante: array_merge() reinicia las claves numéricas y las renumera desde cero. Si tus claves son cadenas, no hay problema. Pero si son numéricas, prepárate para sorpresas:
$original = ['a' => 1, 2 => 'two', 5 => 'five'];\n$copy = array_merge([], $original);\n\nprint_r($copy);\n// Array ( [a] => 1 [0] => two [1] => five )\n\n¿Ves? Las claves 2 y 5 se convirtieron en 0 y 1. Esto puede romper la lógica si el orden de las claves es importante.
\n\nConclusión: array_merge() solo es adecuado para copiar arrays con claves de cadena o cuando la reindexación no es un problema.
Copiar con un bucle: control manual
\n\nLa forma más confiable, aunque también la más verbosa, es recorrer el array con un bucle:
\n\n$original = ['x' => 10, 'y' => 20];\n$copy = [];\n\nforeach ($original as $key => $value) {\n $copy[$key] = $value;\n}\n\n$copy['x'] = 100;\nprint_r($original['x']); // 10\n\nPara arrays simples, esto es redundante. Pero si necesitas hacer una copia profunda (deep copy), entonces sin recurs