2013-09-26 10 views
5

PHPで配列にアクセスする際に問題があります。動的パスを使用したアクセス配列

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

上記のコードでは、私は$ arrayという多次元配列を持っています。

$pathは、データベースから取得する動的な値です。

今私は$ pathを使って$ arrayから値を取得したいが、できない。

$value = $array.$path 

は値ではなく、私に

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

を返します。

私は私の質問を適切に説明してくれることを願っています。

+0

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

+0

私は試みましたが、$ array [['a'] ['b'] ['c']]のようなものを解釈します。それは私のためには機能しません –

+0

'$ path = ['a'] ['b'] ['c']'は有効なPHP構文ではありません。それは文字列ですか? –

答えて

11

2つのオプションがあります。 eval()機能を使用する場合は最初に(悪)、つまり文字列をコードと解釈します。

第2はあなたのパスを解析することです。それは次のようになります。

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

マイナーな改善は '\ [(\ * | ')(。*?)\]'と '$ rgMathces [2]'を使用することです。 –

+0

あなたのコードは、 $ rgResult ['a'] ['b']を入力してから$ rgResult ['b']を選択し、$ rgResult ['c']を入力します。$ rgResult ['a'] ['b'] ['c'] –

+0

@ExplosionPills実際、私のコードはちょうどアイデアを解析するためのサンプルです。実際の状況は –

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

私は未定義のインデックスエラーをスローせずに、ネストされた配列のアクセスにエレガントな解決策を見つけることを期待していた、とこの記事は、Googleで高いヒット。私はパーティーに遅れていますが、私は将来の訪問者のために体重を増やしたいと思いました。

単純な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(); 
} 
} 
関連する問題