2013-09-26 58 views
5

我在访问php中的数组时遇到问题。使用动态路径访问数组

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

在上面的一段代码中,我有一个名为$ array的多维数组。

$path是我从数据库中得到的一个动态值。

现在我想使用$ path从$ array中检索值,但是我不能。

$value = $array.$path 

返回我

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

而不是值。

我希望我已经正确地解释了我的问题。

+0

尝试$ value = $ array [$ path]; – Pupil

+0

我试过了,但它解释了$ array [['a'] ['b'] ['c']]。所以它不适用于我 –

+0

'$ path = ['a'] ['b'] ['c']'是无效的PHP语法。它是一个字符串吗? –

回答

11

你有两种选择。第一个(邪恶)如果使用eval()函数 - 即将您的字符串解释为代码

其次是解析你的路径。这将是:

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

稍微改进是使用'\ [(\“|')(。*?)(\ 1)\]'和$ rgMathces [2]' –

+0

您的代码以垂直方式工作,为$ rgResult ['a']然后$ rgResult ['b']然后$ rgResult ['c']。我想$ rgResult ['a'] ['b'] ['c'] –

+0

@ExplosionPills其实,我的代码只是一个解析想法的例子。真实情况可能会更复杂(如'$ path =“[$ a [$ b] [$ c [$ d]]] [$ e]”'e t.c.) –

2

Kohana framework "Arr" class (API)有做类似于您要求什么东西的方法(Arr::path)。它只需要一个数组和一个路径(以.作为分隔符)并返回值(如果找到)。您可以修改此方法以满足您的需求。

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

我希望找到一个优雅的解决方案嵌套数组访问没有抛出未定义的索引错误,并且这篇文章在谷歌上高点。我迟到了参加派对,但我想为未来的参观者考虑。

简单的isset($array['a']['b']['c']可以安全地检查嵌套值,但您需要知道提前访问的元素。我喜欢用于访问多维数组的点符号,所以我写了一个我自己的类。它确实需要PHP 5.6。

该类解析用点符号编写的字符串路径,并安全地访问数组或类似数组的对象(实现ArrayAccess)的嵌套值。如果未设置,它将返回值或NULL。

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