Как реализовать Dot-notation в перебираемом массиве?
Есть ли интерфейс для реализиации такой возможности? Гуглил - не нашел.
$collection['root.name']; // работает благодаря ArrayAccess
foreach ($collection as $value)
echo $value['foo.bar.baz']; // не работает, т.к. это уже не объект коллекции
и не сильно ли накладно, на каждую итерацию создавать объект?
В классе, реализующем ArrayAccess, в методе offsetSet отщепляешь левую часть ключа до точки, далее:
- Если у ключа не осталось правой части (то есть нет точек) - просто задаешь значение по ключу у $this -> collection (ну или как у тебя поле со значениями обозвано)
- Если осталась - при отсутствии значения по ключу инициализируешь его как new static
- Задаешь значение в дочерней коллекции по оставшемуся "хвосту" ключа
Ну и как offsetGet при этом реализовать, думаю, понятно.
Они реализованы. Просто при переборе коллекции, в $value обычный массив, а не new static $value. Хотелось бы при переборе коллекции иметь ее объекты, а не обычный массив $this-items.
Roquie: Ну так такая реализация как раз решит проблему. У тебя в таком случае только непосредственно значения будут лежать в нативном массиве, а вложенные колллекции у тебя автоматом будут создаваться как экземпляры того же класса, к которым как раз можно обращаться как ты хочешь.
Тимофей: унаследовался от laravel\Support\Collection:
/**
* Set the item at a given offset.
*
* @param mixed $key
* @param mixed $value
* @return void
*/
public function offsetSet($key, $value)
{
array_set($this->items, $key, $value);
}
/**
* Unset the item at a given offset.
*
* @param string $key
* @return void
*/
public function offsetUnset($key)
{
//unset($this->items[$key]);
// Recursive call
if (is_array($key))
foreach ($key as $k)
$this->internalRemove($this->items, $k);
$this->internalRemove($this->items, $key);
}
/**
* @see: https://github.com/Anahkiasen/underscore-php/blob/master/src/Methods/CollectionMethods.php
* @param $collection
* @param $key
* @return bool
*/
protected function internalRemove(&$collection, $key)
{
// Explode keys
$keys = explode('.', $key);
// Crawl though the keys
while (count($keys) > 1) {
$key = array_shift($keys);
// If we're dealing with an object
if (is_object($collection)) {
if (!isset($collection->$key)) {
return false;
}
$collection = &$collection->$key;
// If we're dealing with an array
} else {
if (!isset($collection[$key])) {
return false;
}
$collection = &$collection[$key];
}
}
$key = array_shift($keys);
if (is_object($collection)) {
unset($collection->$key);
} else {
unset($collection[$key]);
}
}
/**
* Get an item at a given offset using Dot-notation.
*
* @param mixed $key
* @return Collection|bool|string
*/
public function offsetGet($key)
{
$result = array_get($this->items, $key);
if (is_array($result))
return new static($result);
return $result;
}
/**
* Get an item from the collection by key using Dot-notation.
*
* @param mixed $key
* @param mixed $default
* @return Collection|bool|string|Closure
*/
public function get($key, $default = null)
{
if ($this->offsetExists($key))
{
return $this->offsetGet($key);
}
return value($default);
}
/**
* Determine if an item exists at an offset.
*
* @param mixed $key
* @return bool
*/
public function offsetExists($key)
{
return (bool) array_get($this->items, $key);
}
поидее, работать должно, но нет. Функции array_get, array_set есть взяты из laravel\support;