我正在使用一个PHP框架,它将SQL结果作为可迭代对象返回。问题是我有一个返回一行的SQL查询,我不想创建一个foreach
- 循环来获取第一个 - 也是唯一 - 元素。
那我该怎么办?
这些不起作用:
$obj->item(0)->propName;
$obj->next()->propName;
$obj[0]->propName;
有什么想法吗?
答案 0 :(得分:20)
假设“iterable”表示对象实现了Iterator
interface,您可以使用$obj->current()
来检索当前元素,因此$obj->current()->propName
可能是您想要的。
如果已移动迭代器指针(例如,如果它在foreach
中使用,但未重置指针),则可以调用$obj->rewind()
将指针设置回在致电$obj->current()
之前的第一个元素。
答案 1 :(得分:10)
只有两个类接口可以遍历:Iterator和IteratorAggregate(任何其他接口必须实现其中一个)。< / p>
迭代器的第一个元素可以如下获得:
$iterator->rewind();
if (!$iterator->valid()) {
throw new Exception('There is no any element!');
}
$firstElement = $iterator->current();
如果您确定:
$iterator
从未遍历过foreach
,或者是break
,但是从未使用return
或$iterator->next();
停止循环(自PHP 7起point是无关紧要的,因为foreach不会影响指针)$iterator->rewind();
您可以省略上一个示例中的$iterator
。
如果您确定$iterator->valid()
中的元素数量不为零,您甚至可以省略条件块测试$firstElement = $iterator->current();
。
因此,如果保留这些先前的条件,那么您需要的只是:
$iterator = $iteratorAggregate->getIterator();
IteratorAggergate实际上只是Iterator或其他IteratorAggregate的信封。从逻辑上讲,这意味着最后有一个迭代器。
如果你知道迭代器的深度是多少,只需抓住它并使用第一个例子:
$array = iterator_to_array($iteratorAggregate);
// $array is an ordinary array now
if (count($array) === 0) {
throw new Exception('There is no any element!');
}
$firstElement = reset($array);
但如果你现在没有深度,你可以使用一个也适用于迭代器的解决方案:
while ($iterator instanceof \IteratorAggregate) {
$iterator = $iterator->getIterator();
}
// $iterator now contains instance of Iterator
不幸的是如果是biig数组,这有点矫枉过正,因为必须创建所有元素的副本,尽管我们只需要一个。此外,如果迭代器是无限的Generator,你将会耗尽内存。
有一种解决方案可行:
while ($iterator instanceof \IteratorAggregate) {
$iterator = $iterator->getIterator();
}
$iterator->rewind();
if (!$iterator->valid()) {
throw new Exception('There is no any element!');
}
$firstElement = $iterator->current();
我为10000个成员的数组做了一个简单的基准测试,这个解决方案快了近6倍。
因此,适用于所有情况的通用解决方案是:
@IntDef
LLAP
答案 2 :(得分:0)
执行此操作的另一种方法,我个人认为不太冗长,是先将迭代器转换为数组,然后检查该数组是否为空。
$result = iterator_to_array($iterator, true);
if(!empty($result)){
$user = end($result)->id;
}
当您知道迭代器仅返回一个“迭代”时非常有用。但是,如果要有成千上万个,请小心,首先要用所有数据填充数组,这可能会增加内存使用率,直到该数组再次为空。
答案 3 :(得分:0)
对于任何类型的可迭代对象(array
,Iterator
,IteratorAggregate
),您可以使用以下功能:
/* public static */ function first(iterable $iterable, $default = null) {
foreach ($iterable as $item){
return $item;
}
return $default;
}
如果您希望在iterable为空时引发异常,则可以使用该版本:
/* public static */ function firstOrThrow(iterable $iterable, \Throwable $e) {
foreach ($iterable as $item){
return $item;
}
throw $e;
}
这既适用于数组又适用于迭代器对象,并且在某些情况下也仅计算迭代器中的第一项,可以提高性能。