7

I have an issue in accessing the array in php.

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

In the above piece of code I have an multidimensional array named $array.

$path is a dynamic value which I would get from database.

Now I want to retrieve the value from $array using $path but I am not able to.

$value = $array.$path

returns me

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

rather than the value.

I hope I have explained my question properly.

8
  • try $value = $array[$path]; Commented Sep 26, 2013 at 12:58
  • I tried but it interprets something like $array[['a']['b']['c']]. So it doesn't work for me Commented Sep 26, 2013 at 12:59
  • $path = ['a']['b']['c'] is not valid PHP syntax. Is it a string? Commented Sep 26, 2013 at 13:00
  • that's not a valid syntax, sorry Commented Sep 26, 2013 at 13:00
  • yes thats a string. sorry for wrong syntax but it is something like $path = "['a']['b']['c']"; Commented Sep 26, 2013 at 13:00

3 Answers 3

11

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];
}
Sign up to request clarification or add additional context in comments.

6 Comments

A minor improvement would be to use \[(\"|')(.*?)(\1)\] and $rgMathces[2]
Your code works in a vertical manner that is first it goes for $rgResult['a'] then $rgResult['b'] and then $rgResult['c']. I want $rgResult['a']['b']['c']
@ExplosionPills Actually, my code is just a sample for parsing idea. Real situation could be more complicated (such as $path = "[$a[$b][$c[$d]]][$e]" e t.c.)
Thats true. Really thanks for your effort, but it doesn't solve my problem. :(
@AbhishekSanghvi no. It will act directly as you needed since each time $rgResult is overwritten by itself. If it is not a solution to your issue - then, clarify what's wrong
|
3

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

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.