Access array using dynamic path

前端 未结 3 433
攒了一身酷
攒了一身酷 2020-12-11 05:58

I have an issue in accessing the array in php.

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

In the above piece of code I hav

相关标签:
3条回答
  • 2020-12-11 06:04

    You have two options. First (evil) if to use eval() function - i.e. interpret your string as code.

    Second is to parse your path. That will be:

    //$path = "['a']['b']['c']";
    preg_match_all("/\['(.*?)'\]/", $path, $rgMatches);
    $rgResult = $array;
    foreach($rgMatches[1] as $sPath)
    {
       $rgResult=$rgResult[$sPath];
    }
    
    0 讨论(0)
  • 2020-12-11 06:04

    The Kohana framework "Arr" class (API) has a method (Arr::path) that does something similar to what you are requesting. It simply takes an array and a path (with a . as delimiter) and returns the value if found. You could modify this method to suit your needs.

    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 讨论(0)
  • 2020-12-11 06:21

    I was hoping to find an elegant solution to nested array access without throwing undefined index errors, and this post hits high on google. I'm late to the party, but I wanted to weigh in for future visitors.

    A simple isset($array['a']['b']['c'] can safely check nested values, but you need to know the elements to access ahead of time. I like the dot notation for accessing multidimensional arrays, so I wrote a class of my own. It does require PHP 5.6.

    This class parses a string path written in dot-notation and safely accesses the nested values of the array or array-like object (implements ArrayAccess). It will return the value or NULL if not set.

    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();
    }
    }
    
    0 讨论(0)
提交回复
热议问题