2012-07-02 19 views
7

Sto cercando di inserire in un array ad un certo punto:PHP: inserimento di un riferimento in un array?

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

Perché cercare di inserirlo nel array con giunzione fallire e con il primo metodo non?

risposta

6

La risposta rapida e-sporca, ma si prega di essere consapevole del fatto che chiamare questa funzione con un riferimento è deprecato e può (a seconda della configurazione di PHP) generano un avvertimento:

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

Il hows- e-perché risponde: quello che sta succedendo è piuttosto sottile. Quando esegui la giunzione, poiché hai inserito un riferimento in quella posizione, $ var2 viene effettivamente riassegnato. È possibile verificare con il seguente codice:

<?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)); 
?> 

si otterrà il seguente risultato:

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

noti che prima della giunzione, $ var2 era una stringa, proprio come vi aspettavate di essere ('Il prossimo'). Dopo la giunzione, tuttavia, $ var2 è stata sostituita con un array contenente un elemento, la stringa 'next'.

Credo che ciò che è la causa è ciò che la documentazione dice: "Se la sostituzione non è un array, verrà typecast a uno (vale a dire (array) $ parametro)" Quindi, ciò che sta accadendo è questo:

  • si sta passando & $ var2 in array come sostituzione.
  • Internamente, php sta convertendo & $ var2 in array (& $ var2). Potrebbe effettivamente fare qualcosa che è equivalente a $ param = array ($ param), il che significa che & $ var2 sarà impostato su array (& $ var2), e poiché è un riferimento e non una copia di $ var2 come normalmente sarebbe, questo sta influenzando la variabile che normalmente sarebbe al di fuori della portata della chiamata.
  • Ora sposta questo nuovo valore di $ var2 nella posizione finale e inserisce una copia di $ var2 nella seconda posizione.

Non sono sicuro di conoscere esattamente la magia di ciò che accade internamente, ma $ var viene definitivamente riassegnato durante la giunzione.Si noti che se si utilizza una terza variabile, poiché non è l'assegnazione di qualcosa a qualcosa che già esiste come riferimento, funziona come previsto:

<?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 il risultato:

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

P.S. Penso che la ragione per cui la chiamata con array (& $ var2) funzioni è perché internamente, splice non deve convertire & $ var2 in array (& $ var2) probabilmente attraverso l'autoassegnazione, cambiando così $ var2 nel processo . Stai creando in modo esplicito un nuovo array di simboli (& $ var2) fisicamente separato in memoria senza bisogno di autoassegnazione. –

+0

P.P.S. Questo tipo di effetto collaterale non intenzionale è precisamente il motivo per cui il pass-by-reference del tempo di chiamata è stato deprecato. ;) –

+0

@AndyLobel dovresti cambiare la risposta accettata a questa. – Hamish

2

Potrebbe essere necessario rendere l'ultimo argomento un array, altrimenti in base allo manual verrà convertito in uno solo.

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

tehe ben fatto;) –

+0

soluzione è corretta, ma per di @ Travesty3 ragione. Il typecasting non è un problema: è il tempo di passare per riferimento che non riesce. – Hamish

+0

dal manuale: 'Se la sostituzione è solo un elemento, non è necessario posizionare array() attorno ad esso, a meno che l'elemento sia un array stesso, un oggetto o NULL. – alfasin

1

Quando provo un esempio come il vostro, Ho ricevuto un avviso che dice "Call-time pass-by-di riferimento è stato sconsigliato." Secondo this answer:

È possibile impostare allow_call_time_pass_reference su true nel file php.ini. Ma è un hack.

0

Qui sto iterazione una matrice ($ values_arr) e la memorizzazione dei riferimenti di ciascuna variabile in un altro array ($ param). È possibile modificare l'utilizzo secondo le proprie esigenze.

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

Risultato

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