2012-07-02 13 views
7

Estoy intentando insertar en una matriz en un momento determinado:PHP: ¿Insertar una referencia en una matriz?

$hi = "test"; 
$var2 = "next"; 
$arr = array(&$hi); 
$arr[] = &$var2; // this works 
array_splice($arr, 1, 0, &$var2); // this doesn't 

¿Por qué tratar de insertarlo en la matriz con empalme fallar y utilizando el primer método no?

Respuesta

6

La respuesta rápida y sucia, pero por favor, tenga en cuenta que llamar a esta función con una referencia es obsoleto y puede (dependiendo de la configuración php) generar una advertencia:

array_splice($arr, 1, 0, array(&$var2)); 

El hows- y-por qué responder: lo que está sucediendo es bastante sutil. Cuando realiza el empalme, porque ha insertado una referencia en esa posición, $ var2 en realidad se está reasignando. Puede verificarlo con el siguiente código:

<?php 
    $hi = "test"; 
    $var2 = "next"; 
    $arr = array(&$hi); 
    $arr[] = &$var2; // this works 
    printf("=== var2 before splice:\n%s\n", var_export($var2, TRUE)); 
    array_splice($arr, 1, 0, &$var2); // this doesn't 
    printf("=== var2 after splice:\n%s\n", var_export($var2, TRUE)); 
?> 

obtendrá el siguiente resultado:

=== var2 before splice: 
'next' 
=== var2 after splice: 
array (
    0 => 'next', 
) 

en cuenta que antes del empalme, $ var2 era una cadena, tal como se esperaba que fuera ('siguiente'). Sin embargo, después del empalme, $ var2 ha sido reemplazado por una matriz que contiene un elemento, la cadena 'siguiente'.

Creo que lo que está causando es lo que dice la documentación: "Si reemplazo no es una matriz, se convertirá a uno (es decir, (matriz) $ parámetro)". Así que lo que está ocurriendo es la siguiente:

  • Usted está pasando & $ var2 en una matriz como la sustitución .
  • Internamente, php está convirtiendo & $ var2 en una matriz (& $ var2). En realidad podría estar haciendo algo que sea equivalente a $ param = array ($ param), lo que significa que & $ var2 se establecerá en array (& $ var2), y dado que es una referencia y no una copia de $ var2 como normalmente sería, esto está afectando a la variable que normalmente estaría fuera del alcance de la llamada.
  • Ahora mueve este nuevo valor de $ var2 a la posición final e inserta una copia de $ var2 en la segunda posición.

No estoy seguro de toda la magia de lo que sucede internamente, pero $ var definitivamente se reasigna durante el empalme.Tenga en cuenta que si se utiliza una tercera variable, ya que no es la asignación de algo a algo que ya existe como una referencia, funciona como se esperaba:

<?php 
    $hi = "test"; 
    $var2 = "next"; 
    $var3 = "last"; 
    $arr = array(&$hi); 
    $arr[] = &$var2; // this works 
    array_splice($arr, 1, 0, &$var3); 
    printf("=== arr is now\n%s\n", var_export($arr, TRUE)); 
?> 

genera el resultado:

=== arr is now 
array (
    0 => 'test', 
    1 => 'last', 
    2 => 'next', 
) 
+0

P.S. Creo que la razón por la que llamarlo con array (& $ var2) es porque internamente, splice no tiene que convertir & $ var2 a array (& $ var2) probablemente a través de la autoasignación, cambiando $ var2 en el proceso . Está creando explícitamente una nueva matriz de símbolos (& $ var2) que está físicamente separada en la memoria sin necesidad de autoasignación. –

+0

P.P.S. Este tipo de efecto colateral involuntario es precisamente por el que la referencia de paso de llamada ha quedado obsoleta. ;) –

+0

@AndyLobel debes cambiar la respuesta aceptada a esta. – Hamish

2

Es posible que tenga que hacer que el último argumento sea una matriz; de lo contrario, de acuerdo con manual, se convertirá en typecasted a uno.

array_splice($arr, 1, 0, array(&$var2)); 
+0

tehe bien hecho;) –

+0

solución es correcta, pero por razones de @ Travesty3. Typecasting no es un problema; es el paso de tiempo de llamada por referencia que falla. – Hamish

+0

del manual: 'Si el reemplazo es solo un elemento, no es necesario colocar array() a su alrededor, a menos que el elemento sea una matriz, un objeto o NULL. – alfasin

1

Cuando trato de un ejemplo como la suya, me sale un aviso que dice "Llamar a tiempo el paso por referencia ha quedado en desuso". De acuerdo con this answer:

Puede establecer allow_call_time_pass_reference como verdadero en su archivo php.ini. Pero es un truco.

0

Aquí estoy iterando una matriz ($ values_arr) y almacenar las referencias de cada variable en otra matriz ($ params). Puede modificar el uso según sus requisitos.

$params = array(); 
$values_arr = array('a', 'b', 123); 
foreach ($values_arr as $key=>&$val) { 
    $params[$key] = &$val; 
} 

Resultado

array (size=3) 
    0 => &string 'a' (length=1) 
    1 => &string 'b' (length=1) 
    2 => &int 123 
Cuestiones relacionadas