Skip to content

Instantly share code, notes, and snippets.

@kijtra
Last active October 28, 2015 04:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kijtra/94a8e574a3a98e64bd51 to your computer and use it in GitHub Desktop.
Save kijtra/94a8e574a3a98e64bd51 to your computer and use it in GitHub Desktop.
[PHP] Access multi-dimensional array using dot separated string. e.g) $obj->get('key1.key2.key3');
<?php
/*
* inspired Slim\Helper\Set
* https://github.com/slimphp/Slim/blob/2.x/Slim/Helper/Set.php
*/
class Data implements \ArrayAccess, \Countable, \IteratorAggregate
{
private $data = array();
private $buffer = array();
public function __construct($data = null)
{
$this->set($data);
}
private function dotToArray($keys)
{
$pos = strpos($keys, '.');
if (false === $pos) {
return false;
}
$key = str_replace('.', '][', $keys) . ']';
$key = substr_replace($key, '', $pos, 1);
parse_str($key . '=', $parsed);
return $parsed;
}
private function setLeaf($array, $value)
{
if (!is_array($array)) {
return $value;
}
$values = array();
foreach($array as $key => $val) {
$values[$key] = $this->setLeaf($val, $value);
}
return $values;
}
public function set($data, $value = null)
{
if (is_array($data)) {
$this->data = array_replace_recursive($this->data, $data);
} elseif(is_string($data)) {
$keys = $data;
if (false === strpos($keys, '.')) {
$this->data[$keys] = $value;
} else {
$values = array();
if ($arr = $this->dotToArray($keys)) {
$values = $this->setLeaf($arr, $value);
} else {
$values[$keys] = $value;
}
$this->data = array_replace_recursive($this->data, $values);
$this->buffer[$keys] = $value;
}
}
return $this;
}
public function get($keys = null)
{
$values = $this->data;
if (empty($values)) {
return null;
} elseif (empty($keys)) {
return $values;
}
elseif (is_string($keys)) {
if (!empty($values[$keys])) {
return $values[$keys];
} elseif (!empty($this->buffer[$keys])) {
return $this->buffer[$keys];
} else {
$value = $values;
foreach (explode('.', $keys) as $key) {
if (!array_key_exists($key, $value)) {
return null;
}
$value = $value[$key];
}
return $this->buffer[$keys] = $value;
}
}
}
public function all()
{
return $this->data;
}
public function has($keys = null)
{
if (empty($keys)) {
return (!empty($this->data));
} elseif (is_string($keys)) {
if (array_key_exists($keys, $this->data)) {
return true;
} elseif (array_key_exists($keys, $this->buffer)) {
return true;
} elseif (false !== strpos($keys, '.')) {
$value = $this->data;
foreach (explode('.', $keys) as $key) {
if (!array_key_exists($key, $value)) {
return false;
}
$value = $value[$key];
}
$this->buffer[$keys] = $value;
return true;
}
}
return false;
}
public function keys($keys = null)
{
$values = $this->data;
if (empty($values)) {
return array();
} elseif (empty($keys)) {
return array_keys($values);
}
elseif (is_string($keys)) {
if (!empty($values[$keys])) {
return array_keys($values[$keys]);
} else {
$value = $values;
foreach (explode('.', $keys) as $key) {
if (!array_key_exists($key, $value)) {
return array();
}
$value = $value[$key];
}
return array_keys($value);
}
}
return array();
}
public function remove($keys)
{
if (empty($this->data)) {
return $this;
} elseif (is_string($keys)) {
if (array_key_exists($keys, $this->buffer)) {
unset($this->buffer[$keys]);
}
if (array_key_exists($keys, $this->data)) {
unset($this->data[$keys]);
} elseif (false !== strpos($keys, '.')) {
$data = $this->data;
$value =& $data;
$count = substr_count($keys, '.');
$bkey = null;
foreach (explode('.', $keys) as $i => $key) {
if (array_key_exists($key, $value)) {
$bkey .= (!$bkey ? NULL : '.').$key;
if (array_key_exists($bkey, $this->buffer)) {
unset($this->buffer[$bkey]);
}
if ($i !== $count) {
$value =& $value[$key];
} else {
unset($value[$key]);
}
}
}
$this->data = $data;
}
}
return $this;
}
/**
* Clear all values
*/
public function clear()
{
$this->data = array();
}
/**
* Property Overloading
*/
public function __get($key)
{
return $this->get($key);
}
public function __set($key, $value)
{
$this->set($key, $value);
}
public function __isset($key)
{
return $this->has($key);
}
public function __unset($key)
{
$this->remove($key);
}
/**
* Array Access
*/
public function offsetExists($offset)
{
return $this->has($offset);
}
public function offsetGet($offset)
{
return $this->get($offset);
}
public function offsetSet($offset, $value)
{
return $this->set($offset, $value);
}
public function offsetUnset($offset)
{
return $this->remove($offset);
}
/**
* Countable
*/
public function count($keys = null)
{
if (empty($keys)) {
return count($this->data);
} elseif($data = $this->get($keys)) {
return count($data);
}
}
/**
* IteratorAggregate
*/
public function getIterator()
{
return new \ArrayIterator($this->data);
}
}
<?php
// Sample base array
$base = array(
'key1' => 'val1',
'key2' => array(
'key2-1' => 123,
'key2-2' => 'abc'
)
);
$obj = new Data($base); // OR $obj->set($base);
// Example 1
var_dump($obj->get('key1'));
/*
string(4) "val1"
*/
// Example 2
var_dump($obj->get('key2.key2-2'));
/*
string(3) "abc"
*/
// Example 3
$obj->set('key3', 'Added val3');
var_dump($obj->all());
/*
array(3) {
["key1"]=>
string(4) "val1"
["key2"]=>
array(2) {
["key2-1"]=>
int(123)
["key2-2"]=>
string(3) "abc"
}
["key3"]=>
string(10) "Added val3"
}
*/
// Example 4
$obj->set('key1', 'Replaced val1');
var_dump($obj->get('key1'));
/*
string(13) "Replaced val1"
*/
// Example 5
$add = array(
'key2-2-1' => 'Added',
'key2-2-2' => 'Added!',
);
$obj->set('key2.key2-3', $add);
var_dump($obj->get('key2'));
/*
array(3) {
["key2-1"]=>
int(123)
["key2-2"]=>
string(3) "abc"
["key2-3"]=>
array(2) {
["key2-2-1"]=>
string(5) "Added"
["key2-2-2"]=>
string(6) "Added!"
}
}
*/
// Example 6
$obj->remove('key2.key2-3.key2-2-1');
var_dump($obj->get('key2'));
/*
array(3) {
["key2-1"]=>
int(123)
["key2-2"]=>
string(3) "abc"
["key2-3"]=>
array(1) {
["key2-2-2"]=>
string(6) "Added!"
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment