복붙노트

키 이름 / 경로로 다차원 배열에 액세스하고 조작하는 방법?

PHP

키 이름 / 경로로 다차원 배열에 액세스하고 조작하는 방법?

필자는 배열 (타겟)의 ​​키 또는 하위 키를 지정하여 점 분리 키 값으로 이름을 전달하는 PHP에서 설정기를 구현해야합니다.

주어진 다음 코드 :

$arr = array('a' => 1,
             'b' => array(
                 'y' => 2,
                 'x' => array('z' => 5, 'w' => 'abc')
             ),
             'c' => null);

$key = 'b.x.z';
$path = explode('.', $key);

$ key의 값에서 $ arr [ 'b'] [ 'x'] [ 'z']의 값 5에 도달하고 싶습니다.

지금.... $ key의 변수 값과 다른 $ arr 값 (깊이가 다른)이 주어진다.

getter get ()에 대해이 코드를 작성했습니다.

public static function get($name, $default = null)
{
    $setting_path = explode('.', $name);
    $val = $this->settings;

    foreach ($setting_path as $key) {
        if(array_key_exists($key, $val)) {
            $val = $val[$key];
        } else {
            $val = $default;
            break;
        }
    }
    return $val;
}

내가 올바른 요소 ($ 키에 있음)에 도달했기 때문에 setter를 작성하는 것이 더 어렵지만 원래 배열에서 값을 설정할 수 없으며 한 번에 키를 지정하는 방법을 알지 못합니다.

어떤 종류의 역 추적을 사용해야합니까? 아니면 피할 수 있습니까?

해결법

  1. ==============================

    1.

    $ path가 이미 explode (또는 함수에 추가)를 통해 배열이라고 가정하면 참조를 사용할 수 있습니다. 잘못된 $ 경로 등의 경우 오류 검사를 추가해야합니다 (isset 생각).

    $key = 'b.x.z';
    $path = explode('.', $key);
    
    function get($path, $array) {
        //$path = explode('.', $path); //if needed
        $temp =& $array;
    
        foreach($path as $key) {
            $temp =& $temp[$key];
        }
        return $temp;
    }
    
    $value = get($path, $arr); //returns NULL if the path doesn't exist
    

    이 조합은 기존 배열에 값을 설정하거나 아직 정의되지 않은 배열을 전달하면 배열을 만듭니다. $ array를 참조 & $ array로 전달하도록 정의하십시오 :

    function set($path, &$array=array(), $value=null) {
        //$path = explode('.', $path); //if needed
        $temp =& $array;
    
        foreach($path as $key) {
            $temp =& $temp[$key];
        }
        $temp = $value;
    }
    
    set($path, $arr);
    //or
    set($path, $arr, 'some value');
    

    이렇게하면 경로의 마지막 키가 설정 해제됩니다.

    function unsetter($path, &$array) {
        //$path = explode('.', $path); //if needed
        $temp =& $array;
    
        foreach($path as $key) {
            if(!is_array($temp[$key])) {
                unset($temp[$key]);
            } else {
                $temp =& $temp[$key];
            }
        }
    }
    unsetter($path, $arr);
    

    * 원래 응답에는 누군가에게 유용 할 경우를 대비하여 내가 남길 몇 가지 제한된 기능이있었습니다.

    세터

    $ array를 참조 & $ array로 전달하도록 정의하십시오 :

    function set(&$array, $path, $value) {
        //$path = explode('.', $path); //if needed
        $temp =& $array;
    
        foreach($path as $key) {
            $temp =& $temp[$key];
        }
        $temp = $value;
    }
    
    set($arr, $path, 'some value');
    

    또는 업데이트 된 배열을 반환하려는 경우 (지루해하기 때문에) :

    function set($array, $path, $value) {
        //$path = explode('.', $path); //if needed
        $temp =& $array;
    
        foreach($path as $key) {
            $temp =& $temp[$key];
        }
        $temp = $value;
    
        return $array;
    }
    
    $arr = set($arr, $path, 'some value');
    

    창조자

    배열을 생성하고 선택적으로 값을 설정하지 않으려면 다음을 수행하십시오.

    function create($path, $value=null) {
        //$path = explode('.', $path); //if needed
        foreach(array_reverse($path) as $key) {
            $value = array($key => $value);
        }
        return $value;
    }    
    
    $arr = create($path);    
    //or
    $arr = create($path, 'some value');
    

    재미있는

    $ array [ 'b'] [ 'x'] [ 'z'];와 같은 것을 구성하고 평가합니다. 주어진 문자열 b.x.z :

    function get($array, $path) {
        //$path = explode('.', $path); //if needed
        $path = "['" . implode("']['", $path) . "']";
        eval("\$result = \$array{$path};");
    
        return $result;
    }
    
  2. ==============================

    2.

    내가 당신을 위해 순수한 PHP가 아니라 솔루션을 OUZO 케이크를 구체적으로 사용하여 배열 :: getNestedValue 메서드 :

    $arr = array('a' => 1,
        'b' => array(
            'y' => 2,
            'x' => array('z' => 5, 'w' => 'abc')
        ),
        'c' => null);
    
    $key = 'b.x.z';
    $path = explode('.', $key);
    
    print_r(Arrays::getNestedValue($arr, $path));
    

    마찬가지로 중첩 된 값을 설정해야하는 경우 Arrays :: setNestedValue 메서드를 사용할 수 있습니다.

    $arr = array('a' => 1,
        'b' => array(
            'y' => 2,
            'x' => array('z' => 5, 'w' => 'abc')
        ),
        'c' => null);
    
    Arrays::setNestedValue($arr, array('d', 'e', 'f'), 'value');
    print_r($arr);
    
  3. ==============================

    3.

    나는 내가 공유 할 유틸리티를 정기적으로 사용한다. 차이점은 점 표기법 (예 : b.x.z) 대신 배열 액세스 표기법 (예 : b [x] [z])을 사용한다는 것입니다. 문서와 코드를 사용하면 매우 자명합니다.

    <?php
    class Utils {
        /**
         * Gets the value from input based on path.
         * Handles objects, arrays and scalars. Nesting can be mixed.
         * E.g.: $input->a->b->c = 'val' or $input['a']['b']['c'] = 'val' will
         * return "val" with path "a[b][c]".
         * @see Utils::arrayParsePath
         * @param mixed $input
         * @param string $path
         * @param mixed $default Optional default value to return on failure (null)
         * @return NULL|mixed NULL on failure, or the value on success (which may also be NULL)
         */
        public static function getValueByPath($input,$path,$default=null) {
            if ( !(isset($input) && (static::isIterable($input) || is_scalar($input))) ) {
                return $default; // null already or we can't deal with this, return early
            }
            $pathArray = static::arrayParsePath($path);
            $last = &$input;
            foreach ( $pathArray as $key ) {
                if ( is_object($last) && property_exists($last,$key) ) {
                    $last = &$last->$key;
                } else if ( (is_scalar($last) || is_array($last)) && isset($last[$key]) ) {
                    $last = &$last[$key];
                } else {
                    return $default;
                }
            }
            return $last;
        }
    
        /**
         * Parses an array path like a[b][c] into a lookup array like array('a','b','c')
         * @param string $path
         * @return array
         */
        public static function arrayParsePath($path) {
            preg_match_all('/\\[([^[]*)]/',$path,$matches);
            if ( isset($matches[1]) ) {
                $matches = $matches[1];
            } else {
                $matches = array();
            }
            preg_match('/^([^[]+)/',$path,$name);
            if ( isset($name[1]) ) {
                array_unshift($matches,$name[1]);
            } else {
                $matches = array();
            }
            return $matches;
        }
    
        /**
         * Check if a value/object/something is iterable/traversable, 
         * e.g. can it be run through a foreach? 
         * Tests for a scalar array (is_array), an instance of Traversable, and 
         * and instance of stdClass
         * @param mixed $value
         * @return boolean
         */
        public static function isIterable($value) {
            return is_array($value) || $value instanceof Traversable || $value instanceof stdClass;
        }
    }
    
    $arr = array('a' => 1,
                 'b' => array(
                     'y' => 2,
                     'x' => array('z' => 5, 'w' => 'abc')
                 ),
                 'c' => null);
    
    $key = 'b[x][z]';
    
    var_dump(Utils::getValueByPath($arr,$key)); // int 5
    
    ?>
    
  4. ==============================

    4.

    배열의 키가 고유하면 array_walk_recursive를 사용하여 몇 줄의 코드로 문제를 해결할 수 있습니다.

        $arr = array('a' => 1,
            'b' => array(
                'y' => 2,
                'x' => array('z' => 5, 'w' => 'abc')
            ),
            'c' => null);
    
        function changeVal(&$v, $key, $mydata) {
            if($key == $mydata[0]) {
                $v = $mydata[1];
            }
        }
    
        $key = 'z';
        $value = '56';
        array_walk_recursive($arr, 'changeVal', array($key, $value));
    
        print_r($arr);
    
  5. ==============================

    5.

    "getter"로서, 나는 이것을 과거에 사용했습니다 :

    $array = array('data' => array('one' => 'first', 'two' => 'second'));
    
    $key = 'data.one';
    
    function find($key, $array) {
        $parts = explode('.', $key);
        foreach ($parts as $part) {
            $array = $array[$part];
        }
        return $array;
    }
    
    $result = find($key, $array);
    var_dump($result);
    
  6. ==============================

    6.

    정말 간단하고 더러운 해결책이 있습니다 (정말 더럽습니다! 키 값이 신뢰할 수 없다면 사용하지 마십시오!). 배열을 반복하는 것보다 더 효율적일 수 있습니다.

    function array_get($key, $array) {
        return eval('return $array["' . str_replace('.', '"]["', $key) . '"];');
    }
    
    function array_set($key, &$array, $value=null) {
        eval('$array["' . str_replace('.', '"]["', $key) . '"] = $value;');
    }
    

    이 두 함수는 키가 배열의 요소로 PHP 코드로 변환되는 코드 스 니펫에 대한 평가를 수행합니다. 그리고 해당 키에 배열 값을 반환하거나 설정합니다.

  7. ==============================

    7.

    이 함수는 받아 들인 답과 같습니다만, 키가 존재하면 참 / 거짓으로 설정된 세 번째 매개 변수를 참조로 추가합니다

    function drupal_array_get_nested_value(array &$array, array $parents, &$key_exists = NULL) {
      $ref = &$array;
      foreach ($parents as $parent) {
        if (is_array($ref) && array_key_exists($parent, $ref)) {
          $ref = &$ref[$parent];
        }
        else {
          $key_exists = FALSE;
          $null = NULL;
          return $null;
        }
      }
      $key_exists = TRUE;
      return $ref;
    }
    
  8. from https://stackoverflow.com/questions/27929875/how-to-access-and-manipulate-multi-dimensional-array-by-key-names-path by cc-by-sa and MIT lisence