2011-12-02 15 views
5

voglio dinamicamente valore di accesso di variabili, diciamo che ho questa matrice:PHP accesso in modo dinamico il valore della variabile

$aData = array(
    'test' => 123 
); 

approccio standard per stampare la chiave valore test sarebbe:

print $aData['test']; 

Tuttavia, se devo lavorare con la rappresentazione di stringa della variabile (per scopi dinamici)

$sItem = '$aData[\'test\']'; 

Come posso ottenere la stampa aDatachiave denominata test? Nessuno degli esempi forniti di seguito funziona

print $$sItem; 
print eval($sItem); 

Quale sarebbe la soluzione?

risposta

6

Il vostro esempio eval manca il valore di ritorno:

print eval("return $sItem;"); 

dovrebbe farlo:

$aData['test'] = 'foo'; 

$sItem = '$aData[\'test\']'; 

print eval("return $sItem;"); # foo 

Ma non è consigliabile usare eval normalmente. Puoi andare nella cucina dell'inferno con esso perché eval è malvagio.

Invece basta analizzare la stringa e restituiscono il valore:

$aData['test'] = 'foo'; 

$sItem = '$aData[\'test\']'; 

$r = sscanf($sItem, '$%[a-zA-Z][\'%[a-zA-Z]\']', $vName, $vKey); 
if ($r === 2) 
{ 
    $result = ${$vName}[$vKey]; 
} 
else 
{ 
    $result = NULL; 
} 

print $result; # foo 

Questo può essere fatto con qualche altra forma di espressione regolare pure.

Come la sintassi è molto vicino a PHP una realtà un sottoinsieme di esso, c'è qualche alternativa si può fare se si desidera convalidare l'ingresso prima di utilizzare eval. Il metodo è di controllare i token PHP e consentire solo un sottoinsieme. Questo non convalida la stringa (sintassi per esempio e se una variabile è in realtà costituito), ma rende più rigoroso:

function validate_tokens($str, array $valid) 
{ 
    $vchk = array_flip($valid); 
    $tokens = token_get_all(sprintf('<?php %s', $str)); 
    array_shift($tokens); 
    foreach($tokens as $token) 
     if (!isset($vchk[$token])) return false; 
    return true; 
} 

Devi solo dare una serie di gettoni validi per quella funzione. Quelli sono i gettoni di PHP, nel tuo caso questi sono:

T_LNUMBER (305) (probably) 
T_VARIABLE (309) 
T_CONSTANT_ENCAPSED_STRING (315) 

È quindi solo può usare e funziona con le chiavi più complicate così:

$aData['test'] = 'foo'; 
$aData['te\\\'[]st']['more'] = 'bar'; 

$sItem = '$aData[\'test\']'; 
$vValue = NULL; 
if (validate_tokens($sItem, array(309, 315, '[', ']'))) 
{ 
    $vValue = eval("return $sItem;"); 
} 

Ho usato questo in another answer della questione reliably convert string containing PHP array info to array.

+0

@all: grazie a tutti voi ragazzi, da quello che im intenzione di fare (nel quadro generale), è la migliore soluzione per me per usare la funzione eval ... mi dimentico di usare il ritorno – nabizan

1

L'unica soluzione nel tuo caso è utilizzare Eval().

Ma per favore sii molto molto attento quando lo fai! Eval valuterà (ed eseguirà) qualsiasi argomento che gli passi come PHP. Quindi se gli dai qualcosa che viene dagli utenti, chiunque può eseguire qualsiasi codice PHP sul tuo server, il che è ovvio è un buco di sicurezza delle dimensioni del Grand Canyon !.

modifica: sarà necessario inserire una "stampa" o "eco" all'interno della variabile $sItem in qualche modo. Dovrà essere in $sItem ($sItem = 'echo $aData[\'test\']';) o dovrai scrivere il tuo Eval() in questo modo: Eval ('echo ' . $sData).

+0

Non solo eval è possibile – azat

+0

Secondo la sua domanda è. –

+0

vedere il mio commento http://stackoverflow.com/a/8356802/328260 – azat

3

Si può semplicemente usarlo come un array normale:

$key = "test"; 

print $aData[$key]; 

Allo stesso modo $aData potrebbe essere di per sé una voce in un negozio di array più grande.


In alternativa, estraendo le chiavi potenziali array usando un'espressione regolare e che attraversano un array anonimo (dovuto ricordare che nella sua interrogazione, se) con riferimenti sarebbe possibile. Vedi Set multi-dimensional array by key path from array values? e argomenti simili.


Personalmente sto usando un costrutto come questo di utilizzare percorsi variabili dinamiche come varname[keyname] invece (simile a come il PHP interpreta ottenere i parametri). E 'solo un eval in abbigliamento pecore (non sono d'accordo con l'allarmismo eval però):

$val = preg_replace("/^(\w)+(\[(\w+)])$/e", '$\1["\3"]', "aData[test]"); 
+0

A parte il fatto che, probabilmente, si intende print $ ADATA [tasto $], e non $ ADATA [$ test], questa è la soluzione migliore in assoluto . +1 –

+1

Se ignori ciò che viene chiesto, allora è la soluzione migliore, sì! :) –

+0

+1. Penso che questa sia l'unica soluzione ragionevole e funzionante. Indipendentemente da come gli altri hanno suggerito di usare 'eval', nessuno di questi funzionerà per restituire il _key_' test'. Probabilmente si otterrebbe un parsing di stringhe regolari per estrarre la chiave, ma eval non riuscirebbe mai a farlo basandosi sul modo in cui l'OP ha la stringa. – Shef

1
$sItem = '$aData[\'test\']'; 
eval('$someVar = '.$sItem.';'); 
echo $someVar; 

Usa eval() con elevata prudenza come spiegato altri aldready.

4

No eval necessario se si dispone (o può ottenere) il nome della matrice e la chiave in variabili distinte:

$aData = array(
    'test' => 123 
); 

$arrayname = 'aData'; 
$keyname = 'test'; 

print ${$arrayname}[$keyname]; // 123 
1

È possibile utilizzare questo metodo

function getRecursive($path, array $data) { 
     // transform "foo['bar']" and 'foo["bar"]' to "foo[bar]" 
     $path = preg_replace('@\[(?:"|\')(.+)(?:"|\')\]@Uis', '[\1]', $path); 

     // get root 
     $i = strpos($path, '['); 
     $rootKey = substr($path, 0, $i); 
     if (!isset($data[$rootKey])) { 
      return null; 
     } 
     $value = $data[$rootKey]; 

     $length = strlen($path); 
     $currentKey = null; 
     for (; $i < $length; ++$i) { 
      $char = $path[$i]; 

      switch ($char) { 
       case '[': 
        if ($currentKey !== null) { 
         throw new InvalidArgumentException(sprintf('Malformed path, unexpected "[" at position %u', $i)); 
        } 
        $currentKey = ''; 
        break; 
       case ']': 
        if ($currentKey === null) { 
         throw new InvalidArgumentException(sprintf('Malformed path, unexpected "]" at position %u', $i)); 
        } 

        if (!isset($value[$currentKey])) { 
         return null; 
        } 

        $value = $value[$currentKey]; 
        if (!is_array($value)) { 
         return $value; 
        } 

        $currentKey = null; 
        break; 
       default: 
        if ($currentKey === null) { 
         throw new InvalidArgumentException(sprintf('Malformed path, unexpected "%s" at position %u', $char, $i)); 
        } 
        $currentKey .= $char; 
        break; 
      } 
     } 

     if ($currentKey !== null) { 
      throw new InvalidArgumentException('Malformed path, must be and with "]"'); 
     } 

     return $value; 
    } 
+0

Questo è un buon approccio. Un singolo 'preg_match_all' sarebbe comunque sufficiente per ottenere i tasti dell'array in una volta, avidendo il' ['parsing'] '. – mario

+0

@mario grazie.Datemi tali per favore, dato che tale chiave non può esistere nell'array – azat

+0

@mario, Il pcre non funziona – azat

Problemi correlati