我编写了以下函数来平整化数组:
function flatten() {
$args = func_get_args();
$items = array();
for ($i = 0; $i < count($args); $i++) { // <-- (*)
$arg =& $args[$i];
if (is_array($arg))
foreach ($arg as &$item)
$args[] =& $item;
else
$items[] = $arg;
}
return $items;
}
我想用简单的foreach ($args as &$arg)
代替for
行。依据是什么?我曾经写过一个实现Iterator
接口的类,它本质上是foreach
控制结构工作的基础。如果我没记错的话,foreach
控制结构的作用如下:
- 使用
rewind()
方法设置内部索引变量为第一个元素的位置。 - 使用
valid()
方法来测试是否已经到达数组的末尾。如果是,退出。 - 使用' Iterator接口的
key()
和current()
方法来检索数组当前元素的键和值。 - 使用
next()
方法将内部索引变量设置为紧跟当前元素的位置。 - Goto 2。
至少,这就是用户定义类的工作方式。我不太确定它如何与内置数组类型一起工作。它会以同样的方式工作吗?我可以用foreach
代替for
行吗
首先,我应该指出,一般来说,在迭代集合时修改集合的内容被认为是一件"不好的事情"——如果您尝试这样做,许多语言都会抛出异常。然而,PHP不是这些语言之一。
这里有两件事与你的问题相关:
首先,当使用数组时,PHP的foreach生成数组的副本并在其上迭代。在这种情况下,您可以安全地修改原始数组,但您的foreach不会看到任何更改。在您的例子中,这不起作用——您附加到$args末尾的新值不会在foreach中出现。
可以通过迭代数组的引用来强制PHP使用原始数组。在这种情况下,内部行为将变得相关。PHP有一个指向"下一个"数组元素的内部指针。如果您更改了'foreach'已经看到的数组元素的内容,则不会看到更改。如果在当前元素之外的某个地方更改了数组的内容,就会看到这些更改。这个应该为你工作,但我不知道我是否相信它。
for和foreach是可以互换的,但是在这种情况下,您不能将元素添加到args数组中并立即使用foreach处理它们,因此如果使用foreach,您的函数将无法以相同的方式运行。
关于代码有几点需要指出:1)将count($args)放在for循环的第二个参数中意味着它在循环的每次迭代中都被处理,如果你有一个非常大的数组,这可能会很昂贵。
我会在处理循环之前计算args的数量,将其存储在一个变量中并使用它来代替for参数中的count($args),然后每次向args数组中添加新元素时将计数加1。这会更快,使用更少的内存。
$nums = array(1, 2, 3, 4);
$newNum = max($nums) + 1;
foreach ($nums as $num) {
echo $num;
if ($newNum > 10) {
break;
}
$nums[] = $newNum++;
}
print_r($nums);
/* output
1234
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
)
*/
使用foreach ($nums as &$num)
:
/* output
1234567
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
[8] => 9
[9] => 10
)
*/