【问题标题】:Using object implementing ArrayAccess and Iterator as variadic parameter使用实现 ArrayAccess 和 Iterator 的对象作为可变参数
【发布时间】:2016-05-15 09:52:21
【问题描述】:

我有一个实现ArrayAccessIterator 的类。

我正在尝试弄清楚如何将此对象可变参数传递给像 array_merge 这样的本机函数:

array_merge(...$object);

令我失望的是,我收到一条错误消息,指出 $object 不是数组。

array_merge(): Argument #1 is not an array

我已经查看了这些其他接口,但它们似乎都不明显:IteratorAggregateSerializableCountable。还有ArrayObject 原来是死路一条。

我确实有一个用于转换为数组的 getter。但是我有点想通过实现 ArrayAccess 或 Iterator 来发现我的 $object 转换为数组,因为它是关于展开数组。

我可以实现另一个接口来使我的类更像数组吗?

【问题讨论】:

  • 你的$object是一个数组?
  • @GentiSaliu 我的 $object 是一个 ArrayAccess 实现
  • @RyanVincent Underscore.php 与我正在处理的 (arrgh) 类似,所以他们会有同样的问题。
  • 我不知道你实现的对象是什么。当我想要一个实现数组接口的对象时,我要做的是扩展 ArrayObject 并覆盖“offsetGet”等函数。有用的部分是它很容易访问或替换继承的数组(array_copy)。

标签: php arrays variadic


【解决方案1】:

这是the migration guide from 5.5.x to 5.6.x in the manual 中记录的新语言功能(通过... 解包的部分),您必须使用5.6.x 之前的运行时。

如果您无法升级运行时,则必须使用 getter 将其转换为数组(类似于 ArrayObject's getArrayCopy):

call_user_func_array('array_merge', $arr->getArrayCopy());

测试

下面的代码(基于ArrayAccessIterator 的PHP 文档示例)在PHP 5.6.25.6.177.0.1 上成功执行。它在旧版本(5.5.31 和更早版本)上确实失败了。

$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));

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

【讨论】:

  • Iterator 扩展 Traversable。问题不在于在我的对象上使用foreach,而是关于将我的对象用作array_map等本机函数的可变参数。
  • 这是我的确切实现。我意识到我的内部数组包含更多同一个类的对象,因此返回了对象(当然是实现 ArrayAccess,Iterator)。所以我猜结论是 splat 将解包对象,但 array_map 除了原生数组之外仍然不接受:(
  • 我想我正在寻找类似于__toString() 的东西,PHP 在期望找到一个数组时会调用它。 __toArray() 如果你愿意的话。
  • 很遗憾,这无法完成。对此没有什么神奇的方法。 array_maparray_merge 等需要原生 PHP 数组,正如它们的名称所述。另见stackoverflow.com/questions/11121613/…stackoverflow.com/questions/13140657/…
猜你喜欢
  • 2012-04-15
  • 2020-06-26
  • 2011-07-14
  • 2015-01-30
  • 2014-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多