2010-06-30 6 views
15

Scusa se lo chiedo, è tardi e non riesco a immaginare un modo per farlo ... qualcuno può aiutarti?PHP: controlla se object/array è un riferimento

$users = array(
    array(
     "name" => "John", 
     "age" => "20" 
    ), 
    array(
     "name" => "Betty", 
     "age" => "22" 
    ) 
); 

$room = array(
    "furniture" => array("table","bed","chair"), 
    "objects" => array("tv","radio","book","lamp"), 
    "users" => &$users 
); 

var_dump $ sala mostra:

... 
'users' => & 
... 

che significa "utenti" è un punto di riferimento.

vorrei fare qualcosa di simile:

foreach($room as $key => $val) { 
    if(is_reference($val)) unset($room[$key]); 
} 

L'obiettivo principale è quello di copiare l'array senza alcun riferimento.

È possibile?

Grazie.

+2

Il primo commento mostra come si può fare: http://www.php.net/manual /en/language.references.spot.php – pritaeas

+0

Vuoi $ room senza chiave utente, giusto? Ci possono essere altri riferimenti o sarebbero solo utenti? – Gordon

+0

Sì. Il problema è che ho una matrice di grandi dimensioni con molti riferimenti incrociati al suo interno. E voglio prenderne una parte ma senza i riferimenti. Quindi, in breve, la chiave potrebbe essere variabile. Sono piuttosto pigro ora e non voglio rintracciare tutti i riferimenti attuali e futuri. – lepe

risposta

7

È possibile verificare i riferimenti in un array multidimensionale facendo una copia della matrice, e quindi alterando e testare ogni voce, a sua volta:

$roomCopy = $room; 
foreach ($room as $key => $val) { 
    $roomCopy[$key]['_test'] = true; 
    if (isset($room[$key]['_test'])) { 
    // It's a reference 
    unset($room[$key]); 
    } 
} 
unset($roomCopy); 

con i tuoi dati di esempio, $room['furniture'] e $roomCopy['furniture'] sarà array separati (come $roomCopy è una copia di $room), quindi l'aggiunta di una nuova chiave a una non influirà sull'altra. Ma, $room['users'] e $roomCopy['users'] saranno riferimenti allo stesso array $users (poiché è il riferimento che viene copiato, non l'array), quindi quando aggiungiamo una chiave a $roomCopy['users'] è visibile in $room['users'].

+1

Tipo di soluzione sporca ma creativa ... +1 – lepe

+1

Analizzando il collegamento fornito da pritaeas, risulta essere quasi la stessa soluzione di questa, ma più estesa (preferisco comunque questa compilazione ridotta). – lepe

1

forse qualcosa di ricorsivo.

function removeReferences($inbound) 
{ 
    foreach($inbound as $key => $context) 
    { 
     if(is_array($context)) 
     { 
      $inbound[$key] = removeReferences($context) 
     }elseif(is_object($context) && is_reference($context)) 
     { 
      unset($inbound[$key]); //Remove the entity from the array. 
     } 
    } 
    return $inbound; 
} 
+4

Tranne che 'is_reference' non esiste. Ecco cosa sta cercando;) – Chris

+0

sì mio male, l'ho postato e ho cercato di trovare una soluzione, ma il metodo Sporco di Chris Smith sembra l'unico modo – RobertPitt

3

Il meglio che posso gestire è un test di due variabili per determinare se uno è un riferimento all'altro:

$x = "something"; 
$y = &$x; 
$z = "something else"; 

function testReference(&$xVal,&$yVal) { 
    $temp = $xVal; 
    $xVal = "I am a reference"; 
    if ($yVal == "I am a reference") { echo "is reference<br />"; } else { echo "is not reference<br />"; } 
    $xVal = $temp; 
} 

testReference($x,$y); 
testReference($y,$x); 

testReference($x,$z); 
testReference($z,$x); 

testReference($y,$z); 
testReference($z,$y); 

ma dubito se si tratta di molto aiuto

metodo molto sporca (non ben testati):

$x = "something"; 
$y = &$x; 
$z = "something else"; 

function isReference(&$xVal) { 
    ob_start(); 
    debug_zval_dump(&$xVal); 
    $dump = ob_get_clean(); 
    preg_match('/refcount\((\d*)\)/',$dump,$matches); 
    if ($matches[1] > 4) { return true; } else { return false; } 
} 

var_dump(isReference($x)); 
var_dump(isReference($y)); 
var_dump(isReference($z)); 

Per utilizzare quest'ultimo metodo nel codice, è necessario eseguire alcune cosa come:

foreach($room as $key => $val) { 
    if(isReference($room[$key])) unset($room[$key]); 
} 

perché $ val è mai un punto di riferimento in quanto è una copia dell'elemento matrice originale; e l'utilizzo di & $ val rende sempre un riferimento

+0

Per i valori semplici (string, int, ecc.) Il tuo primo metodo potrebbe funzionare (come è fondamentalmente ciò che ha postato Chris), ma non per gli array. Il secondo metodo è interessante l'uso di "refcount" debug_zval_dump. Ma IMHO sarebbe quasi la stessa cosa che analizza il "&" dal risultato var_dump, con la differenza che con questo metodo è possibile ottenere il numero di riferimenti. BTW, il passaggio di riferimenti, come argomento, in funzioni è deprecato. Dovrebbe essere: debug_zval_dump ($ xVal); – lepe

+0

debug_zval_dump() è piuttosto strano per quanto riguarda il pass-by-reference/pass-by-value, e c'è un intero blocco nella documentazione dedicata a quell'argomento. Tuttavia, a meno che non si usi la forma deprecata di pass-by-reference, debug_zval_dump() sembra funzionare su una copia (con un refcount di 1) piuttosto che sulla variabile stessa ... è come un residuo dimenticato del vecchio metodo di passaggio -da-riferimento –

+0

Oh capisco. Interessante... – lepe

1
function var_reference_count(&$xVal) { 
    $ao = is_array($xVal)||is_object($xVal); 

    if($ao) { $temp= $xVal; $xVal=array(); } 

    ob_start();   
    debug_zval_dump(&$xVal); 
    $dump = ob_get_clean(); 

    if($ao) $xVal=$temp; 

    preg_match('/refcount\((\d*)\)/',$dump,$matches); 
    return $matches[1] - 3; 
} 
//------------------------------------------------------------------------------------------- 

Questo funziona con gli oggetti e gli array hudge.

0

se si vuole sbarazzarsi di elementi ricorsivi:

<?php 
$arr=(object)(NULL); $arr->a=3; $arr->b=&$arr; 
//$arr=array('a'=>3, 'b'=>&$arr); 
print_r($arr); 

$arr_clean=eval('return '.strtr(var_export($arr, true), array('stdClass::__set_state'=>'(object)')).';'); 
print_r($arr_clean); 
?> 

uscita:

stdClass Object ([a] => 3 [b] => stdClass Object *RECURSION*) 
stdClass Object ([a] => 3 [b] =>)