I have a class that implements both ArrayAccess and Iterator.
I'm trying to figure out how to pass this object variadic parameter to a native function like array_merge
:
array_merge(...$object);
To my disappointment I'm getting an error saying that $object
is not an array.
array_merge(): Argument #1 is not an array
I've looked at these other interfaces but non of them seem obvious: IteratorAggregate, Serializable, Countable. Also ArrayObject turned out to be a dead end.
I do have a getter for to convert to array. But I was kind of hopping to discover my $object transform into an array just by implementing either ArrayAccess or Iterator, since it is about unfolding the array.
Is there another interface I can implement to make my class be more array-like?
This is a new language feature as documented in the migration guide from 5.5.x to 5.6.x in the manual (section Argument unpacking via ...
), you must be on a pre-5.6.x
runtime.
If you cannot upgrade your runtime, you must make use of your getter for converting it to an array (similar to ArrayObject
's getArrayCopy
):
call_user_func_array('array_merge', $arr->getArrayCopy());
Tests
The code below (based on PHP's documentation examples for ArrayAccess
and Iterator
) executed successfully on PHP 5.6.2
, 5.6.17
and 7.0.1
. It fails indeed on older versions (5.5.31
and older).
$arr = new MyArray();
$arr[0] = array(1, 2);
$arr[1] = array(3, 4);
// MyArray
print(get_class($arr));
// Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 )
print_r(array_merge(...$arr));
Implementation of MyArray
:
class MyArray implements ArrayAccess, Iterator
{
private $container = array();
private $position = 0;
public function getArrayCopy() {
return $this->container;
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function offsetGet($offset) {
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
function rewind() {
$this->position = 0;
}
function current() {
return $this->container[$this->position];
}
function key() {
return $this->position;
}
function next() {
++$this->position;
}
function valid() {
return isset($this->container[$this->position]);
}
}