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