2013-09-26 16 views
5

Ho riscontrato un problema nell'accesso all'array in php.Accesso array tramite percorso dinamico

$path = "['a']['b']['c']"; 
$value = $array.$path; 

Nella parte di codice precedente ho un array multidimensionale denominato $ array.

$path è un valore dinamico che otterrei dal database.

Ora voglio recuperare il valore da $ array utilizzando $ percorso ma non riesco a.

$value = $array.$path 

mi restituisce

Array['a']['b']['c'] 

piuttosto che il valore.

Spero di aver spiegato correttamente la mia domanda.

+0

try $ value = $ array [$ path]; – Pupil

+0

Ho provato ma interpreta qualcosa come $ array [['a'] ['b'] ['c']]. Quindi non funziona per me –

+0

'$ path = ['a'] ['b'] ['c']' non è una sintassi PHP valida. È una stringa? –

risposta

11

Hai due opzioni. Primo (male) se utilizzare la funzione eval() - ad esempio, interpretare la stringa come codice.

Secondo è analizzare il percorso. Che sarà:

//$path = "['a']['b']['c']"; 
preg_match_all("/\['(.*?)'\]/", $path, $rgMatches); 
$rgResult = $array; 
foreach($rgMatches[1] as $sPath) 
{ 
    $rgResult=$rgResult[$sPath]; 
} 
+0

Un miglioramento minore sarebbe l'uso di '\ [(\" | ') (. *?) (\ 1) \] 'e' $ rgMathces [2] ' –

+0

Il tuo codice funziona in modo verticale che prima va avanti per $ rgResult ['a'] quindi $ rgResult ['b'] e poi $ rgResult ['c']. Voglio $ rgResult ['a'] ['b'] ['c'] –

+0

@ExplosionPills In realtà, il mio codice è solo un esempio per l'idea di analisi.La situazione reale potrebbe essere più complicata (come "$ percorso =" [$ a [$ b] [$ c [$ d]]] [$ e] "' e t.c.) –

2

Il Kohana framework "Arr" class (API) ha un metodo (Arr::path) che fa qualcosa di simile a quello che si richiede. Prende semplicemente un array e un percorso (con un delimitatore .) e restituisce il valore se trovato. È possibile modificare questo metodo in base alle proprie esigenze.

public static function path($array, $path, $default = NULL, $delimiter = NULL) 
{ 
    if (! Arr::is_array($array)) 
    { 
     // This is not an array! 
     return $default; 
    } 

    if (is_array($path)) 
    { 
     // The path has already been separated into keys 
     $keys = $path; 
    } 
    else 
    { 
     if (array_key_exists($path, $array)) 
     { 
      // No need to do extra processing 
      return $array[$path]; 
     } 

     if ($delimiter === NULL) 
     { 
      // Use the default delimiter 
      $delimiter = Arr::$delimiter; 
     } 

     // Remove starting delimiters and spaces 
     $path = ltrim($path, "{$delimiter} "); 

     // Remove ending delimiters, spaces, and wildcards 
     $path = rtrim($path, "{$delimiter} *"); 

     // Split the keys by delimiter 
     $keys = explode($delimiter, $path); 
    } 

    do 
    { 
     $key = array_shift($keys); 

     if (ctype_digit($key)) 
     { 
      // Make the key an integer 
      $key = (int) $key; 
     } 

     if (isset($array[$key])) 
     { 
      if ($keys) 
      { 
       if (Arr::is_array($array[$key])) 
       { 
        // Dig down into the next part of the path 
        $array = $array[$key]; 
       } 
       else 
       { 
        // Unable to dig deeper 
        break; 
       } 
      } 
      else 
      { 
       // Found the path requested 
       return $array[$key]; 
      } 
     } 
     elseif ($key === '*') 
     { 
      // Handle wildcards 

      $values = array(); 
      foreach ($array as $arr) 
      { 
       if ($value = Arr::path($arr, implode('.', $keys))) 
       { 
        $values[] = $value; 
       } 
      } 

      if ($values) 
      { 
       // Found the values requested 
       return $values; 
      } 
      else 
      { 
       // Unable to dig deeper 
       break; 
      } 
     } 
     else 
     { 
      // Unable to dig deeper 
      break; 
     } 
    } 
    while ($keys); 

    // Unable to find the value requested 
    return $default; 
} 
0

speravo di trovare una soluzione elegante per l'accesso array nidificato senza gettare errori indice indefiniti, e questo post colpisce alto su google. Sono in ritardo per la festa, ma volevo pesare per i futuri visitatori.

Un semplice isset($array['a']['b']['c'] può controllare in sicurezza i valori nidificati, ma è necessario conoscere gli elementi per accedere in anticipo. Mi piace la notazione dot per l'accesso a array multidimensionali, quindi ho scritto una classe a mia volta. Richiede PHP 5.6.

Questa classe analizza un percorso di stringa scritto in dot-notation e accede in modo sicuro ai valori nidificati dell'array o dell'oggetto simile all'array (implementa ArrayAccess). Restituirà il valore o NULL se non impostato.

use ArrayAccess; 

class SafeArrayGetter implements \JsonSerializable { 

/** 
* @var array 
*/ 
private $data; 

/** 
* SafeArrayGetter constructor. 
* 
* @param array $data 
*/ 
public function __construct(array $data) 
{ 
    $this->data = $data; 
} 

/** 
* @param array $target 
* @param array ...$indices 
* 
* @return array|mixed|null 
*/ 
protected function safeGet(array $target, ...$indices) 
{ 
    $movingTarget = $target; 

    foreach ($indices as $index) 
    { 
     $isArray = is_array($movingTarget) || $movingTarget instanceof ArrayAccess; 
     if (! $isArray || ! isset($movingTarget[ $index ])) return NULL; 

     $movingTarget = $movingTarget[ $index ]; 
    } 

    return $movingTarget; 
} 

/** 
* @param array ...$keys 
* 
* @return array|mixed|null 
*/ 
public function getKeys(...$keys) 
{ 
    return static::safeGet($this->data, ...$keys); 
} 

/** 
* <p>Access nested array index values by providing a dot notation access string.</p> 
* <p>Example: $safeArrayGetter->get('customer.paymentInfo.ccToken') == 
* $array['customer']['paymentInfo']['ccToken']</p> 
* 
* @param $accessString 
* 
* @return array|mixed|null 
*/ 
public function get($accessString) 
{ 
    $keys = $this->parseDotNotation($accessString); 

    return $this->getKeys(...$keys); 
} 

/** 
* @param $string 
* 
* @return array 
*/ 
protected function parseDotNotation($string) 
{ 
    return explode('.', strval($string)); 
} 

/** 
* @return array 
*/ 
public function toArray() 
{ 
    return $this->data; 
} 

/** 
* @param int $options 
* @param int $depth 
* 
* @return string 
*/ 
public function toJson($options = 0, $depth = 512) 
{ 
    return json_encode($this, $options, $depth); 
} 

/** 
* @param array $data 
* 
* @return static 
*/ 
public static function newFromArray(array $data) 
{ 
    return new static($data); 
} 

/** 
* @param \stdClass $data 
* 
* @return static 
*/ 
public static function newFromObject(\stdClass $data) 
{ 
    return new static(json_decode(json_encode($data), TRUE)); 
} 

/** 
* Specify data which should be serialized to JSON 
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php 
* @return array data which can be serialized by <b>json_encode</b>, 
* which is a value of any type other than a resource. 
* @since 5.4.0 
*/ 
function jsonSerialize() 
{ 
    return $this->toArray(); 
} 
}