2011-12-02 10 views
5

Quiero dinámicamente valor de acceso de la variable, digamos que tengo esta matriz:PHP para acceder dinámicamente valor de la variable

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

enfoque estándar para imprimir el valor clave test sería:

print $aData['test']; 

Sin embargo, si tengo que trabajar con la representación de cadena de la variable (para fines dinámicos)

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

¿cómo puedo lograr imprimir aDataclave llamada test? Ninguno de los ejemplos proporcionados a continuación funciona

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

¿Cuál sería la solución?

Respuesta

6

Su ejemplo eval es deficiente el valor de retorno:

print eval("return $sItem;"); 

debería hacerlo:

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

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

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

Pero no se recomienda utilizar eval normalmente. Puedes ir a la cocina del infierno con ella porque eval es malvado.

En su lugar sólo analizar la cadena y regresar el valor:

$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 

Esto se puede hacer con cualquier otra forma de expresión regular también.

Como su sintaxis es muy parecida a PHP y en realidad es un subconjunto de ella, hay alguna alternativa que puede hacer si quiere validar la entrada antes de usar eval. El método es verificar contra tokens PHP y solo permite un subconjunto. Esto no valida la cadena (por ejemplo, la sintaxis y si una variable se establece en realidad), pero hace que sea más estricta:

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; 
} 

Usted acaba de dar una serie de símbolos válidos para esa función. Esas son las fichas de PHP, en su caso, estos son:

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

A continuación, sólo se puede usar y funciona con claves más complicados, así:

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

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

He utilizado este en another answer de la cuestión reliably convert string containing PHP array info to array.

+0

@all: gracias a todos ustedes, por lo que planeo hacer (en gran pantalla) es La mejor solución para mí al usar la función eval ... simplemente me olvido de usar return – nabizan

1

La única solución en su caso es usar Eval().

Pero tenga mucho cuidado al hacer esto. Eval evaluará (y ejecutará) cualquier argumento que le pase como PHP. Entonces, si le das algo que proviene de los usuarios, entonces cualquiera puede ejecutar cualquier código PHP en tu servidor, lo que es evidente es un agujero de seguridad del tamaño de Grand Canyon.

editar: tendrá que poner una "impresión" o "eco" dentro de su variable $sItem de alguna manera. O bien tendrá que estar en $sItem ($sItem = 'echo $aData[\'test\']';) o tendrá que escribir su Eval() de esta manera: Eval ('echo ' . $sData).

+0

No sólo eval es posible – azat

+0

Según su pregunta es. –

+0

vea mi comentario http://stackoverflow.com/a/8356802/328260 – azat

3

Puede sólo lo utilizan como una matriz común:

$key = "test"; 

print $aData[$key]; 

Del mismo modo $aData podría ser en sí mismo una entrada en una tienda de matriz más grande.


Como alternativa, la extracción de las claves de matriz potenciales utilizando una expresión regular y atraviesan una serie anónima (debería haber mencionado que en su pregunta, si) con referencias serían posibles. Ver Set multi-dimensional array by key path from array values? y temas similares.


Personalmente estoy usando una construcción como esta para que utilice rutas variables dinámicas como varname[keyname] lugar (similar a la forma en PHP interpreta parámetros GET). Es sólo una eval en ropa de las ovejas (no están de acuerdo con el alarmismo eval sin embargo):

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

Aparte del hecho de que probablemente quiera decir imprimir $ aData [$ key], y no $ aData [$ test], esta es la mejor solución de lejos . +1 –

+1

Si ignora lo que se le pregunta, entonces es la mejor solución, ¡sí! :) –

+0

+1. Creo que esta es la única solución razonable y funcional. No importa cómo los otros hayan sugerido usar 'eval', ninguno de ellos funcionará para devolver el _key_' test'. Probablemente algún análisis de cadena regex lograría extraer la clave, pero eval nunca lograría hacer eso en base a la forma en que el OP tiene la cadena. – Shef

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

Use eval() con mucha precaución como otros aldready explicó.

4

n eval necesario si usted tiene (o puede obtener) el nombre de la matriz y la clave en variables independientes:

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

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

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

podría utilizar este método

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

Ese es un buen enfoque. Sin embargo, un solo 'preg_match_all' sería suficiente para obtener las claves de la matriz a la vez, avoding the' ['parsing'] '. – mario

+0

@mario gracias.Dame tal por favor, dado que tal clave no puede existir en el arreglo – azat

+0

@mario, Tu pcre no funciona – azat

Cuestiones relacionadas