循環是程序控制流的基石。PHP 提供四種核心循環結構,各有適用場景與效能特徵。本文對比語法、語義、效能,給出選型指南。
// for:已知次數或需索引控制
for ($i = 1; $i <= 5; $i++) { echo $i; }
// while:條件驅動,可能零次執行
$i = 1;
while ($i <= 5) { echo $i++; }
// do-while:至少執行一次
$i = 0;
do { echo ++$i; } while ($i < 5);
// foreach:專為陣列/可遍歷對象設計
foreach ($arr as $k => $v) { echo "$k=$v"; }
結論先行:唯讀遍歷用 foreach,寫入遍歷用 while(list()/each()) 或 for。
| 操作類型 | 推薦 | 原因 |
|---|---|---|
| 唯讀 | foreach | Copy-on-Write 機制,值未修改不複製,極快 |
| 寫入(修改值) | while/for | foreach 需 &$v 否則修改副本;while 直接操作原陣列 |
// 唯讀:foreach 勝出
foreach ($arr as $v) { echo $v; }
// 寫入:while + list/each(PHP 7.2+ 棄用 each,改用 for/foreach 引用)
// 現代寫法:
foreach ($arr as $k => &$v) { $v = strtoupper($v); }
unset($v);
// 或
for ($i = 0, $len = count($arr); $i < $len; $i++) {
$arr[$i] = strtoupper($arr[$i]);
}
function file_list(string $dir, string $pattern = ''): array {
$result = [];
$handle = opendir($dir);
if (!$handle) return $result;
while (($file = readdir($handle)) !== false) {
if ($file === '.' || $file === '..') continue;
$path = $dir . '/' . $file;
if (is_dir($path)) {
$result = array_merge($result, file_list($path, $pattern));
} elseif ($pattern === '' || preg_match($pattern, $path)) {
$result[] = $path;
}
}
closedir($handle);
return $result;
}
// 使用:列出所有 .php 文件
print_r(file_list($_SERVER['DOCUMENT_ROOT'], '/\.php$/i'));
PHP 5.5+ yield 可構建生成器,逐個產出值,極大降低內存佔用:
function file_gen(string $dir): Generator {
$handle = opendir($dir);
while (($file = readdir($handle)) !== false) {
if ($file === '.' || $file === '..') continue;
$path = $dir . '/' . $file;
if (is_dir($path)) {
yield from file_gen($path); // 委派生成器
} else {
yield $path;
}
}
closedir($handle);
}
foreach (file_gen('/var/www') as $file) { /* 逐個處理,無需載入全量陣列 */ }
選擇循環結構的原則:語義清晰優先,效能次之。陣列遍歷首選 foreach;計數循環用 for;條件未知用 while;需至少一次用 do-while。大數據集場景引入 Generator 實現流式處理。