IteratorAggregate
是实现迭代器的一种简单方法。缺点是您不能添加next()
,key()
等方法,因为它们不会在正常foreach
遍历期间被调用。
如果你需要实现自定义方法,你需要实现一个OuterIterator
or (更容易)来扩展一个IteratorIterator
.
优点IteratorAggregate
是速度,它比它的替代品快得多。它的问题是......尽管名称不是迭代器,而是可遍历的(同样,没有下一个,键,当前,有效,倒带方法)。
这是我在我可怜的笔记本电脑上运行的一个简单基准测试,每个 100 万次迭代IteratorAggregate
,IteratorIterator
并且OuterIterator
都使用iterator_to_array
和foreach
:
(还要注意echo
内部聚合的next
方法:没有打印'x',证明它从未被调用)
$ repeat 3 php benchIterator.php
------------------------------------
Outer_ToArray: 569.61703300476 ms
Aggregate_ToArray: 552.38103866577 ms
IteratorIt_ToArray: 546.95200920105 ms
Outer_Foreach: 1679.8989772797 ms
IteratorIt_Foreach: 1019.6850299835 ms
Aggregate_Foreach: 367.35391616821 ms
------------------------------------
Outer_ToArray: 570.75309753418 ms
Aggregate_ToArray: 544.40784454346 ms
IteratorIt_ToArray: 555.06300926208 ms
Outer_Foreach: 1682.2130680084 ms
IteratorIt_Foreach: 988.21592330933 ms
Aggregate_Foreach: 356.41598701477 ms
------------------------------------
Outer_ToArray: 566.06101989746 ms
Aggregate_ToArray: 543.1981086731 ms
IteratorIt_ToArray: 546.28610610962 ms
Outer_Foreach: 1663.2289886475 ms
IteratorIt_Foreach: 995.28503417969 ms
Aggregate_Foreach: 356.16087913513 ms
这是我用于基准测试的代码:
<?php
class Aggregate implements \IteratorAggregate
{
protected $var;
public function __construct($var = null)
{
if (is_array($var)) {
$this->var = new ArrayIterator($var);
}
if ($var instanceof \Traversable) {
$this->var = $var;
}
}
public function next()
{
echo 'x';
}
public function toArray()
{
return iterator_to_array($this->var, true);
}
public function getIterator()
{
return $this->var;
}
}
class Outer implements \OuterIterator
{
protected $var;
public function __construct($var = null)
{
if (is_array($var)) {
$this->var = new ArrayIterator($var);
}
if ($var instanceof \Traversable) {
$this->var = $var;
}
}
public function toArray()
{
return iterator_to_array($this->var, true);
}
public function getInnerIterator()
{
return $this->var;
}
public function current()
{
return $this->var->current();
}
public function next()
{
$this->var->next();
}
public function key()
{
return $this->var->key();
}
public function valid()
{
return $this->var->valid();
}
public function rewind()
{
$this->var->rewind();
}
}
class IteratorIt extends IteratorIterator
{
public function __construct($var = null)
{
if (is_array($var)) {
$var = new ArrayIterator($var);
}
parent::__construct($var);
}
public function toArray()
{
return iterator_to_array($this->getInnerIterator(), true);
}
public function getIterator()
{
return $this->getInnerIterator();
}
}
function bench($name, $test)
{
echo "$name: ";
$start = microtime(true);
$test();
$time = microtime(true);
$time -= $start;
echo ($time * 1000) . ' ms' . PHP_EOL;
}
$max = 1e6;
$array = range (1, 1e6);
$testSuites = [
'Outer_ToArray' => function () use ($max, $array) {
$iterator = new Outer($array);
$r = $iterator->toArray();
},
'Aggregate_ToArray' => function () use ($max, $array) {
$iterator = new Aggregate($array);
$r = $iterator->toArray();
},
'IteratorIt_ToArray' => function () use ($max, $array) {
$iterator = new IteratorIt($array);
$r = $iterator->toArray();
},
'Outer_Foreach' => function () use ($max, $array) {
$iterator = new Outer($array);
foreach ($iterator as $k => $v)
{
}
},
'IteratorIt_Foreach' => function () use ($max, $array) {
$iterator = new IteratorIt($array);
foreach ($iterator as $k => $v)
{
}
},
'Aggregate_Foreach' => function () use ($max, $array) {
$iterator = new Aggregate($array);
foreach ($iterator as $k => $v)
{
}
},
];
echo '------------------------------------'.PHP_EOL;
foreach ($testSuites as $name => $test) {
bench($name, $test);
}