PHP基础 流程控制 第六天

for / foreach / break / continue / switch / declare

for

for 循环是 PHP 中最复杂的循环结构。它的行为和   C 语言的相似。 for 循环的语法是:  

for ( 表达式 1; 表达式 2; 表达式3 ) {
  echo  'xlxz';
}

第一个表达式(expr1)在循环开始前无条件求值一次。  

expr2 在每次循环开始前求值。如果值为   TRUE,则继续循环,执行嵌套的循环语句。如果值为 FALSE,则终止循环。

expr3 在每次循环之后被求值(执行)。  

  每个表达式都可以为空或包括逗号分隔的多个表达式。

表达式 expr2中,所有用逗号分隔的表达式都会计算,但只取最后一个结果。

expr2为空意味着将无限循环下去(和 C 一样,PHP 认为其值为   TRUE)。

这可能不像想象中那样没有用,因为经常会希望用 break语句来结束循环而不是用 for 的表达式真值判断。  

  考虑以下的例子,它们都显示数字 1 到 10:

<?php
/* 范例 1 */

for ($i = 1; $i <= 10; $i++) {
    echo $i;
} 

/* 范例 2 */

for ($i = 1; ; $i++) {
    if ($i > 10) {
        break;
    }
    echo $i;
} 

/* 范例 3 */

$i = 1;
for (;;) {
    if ($i > 10) {
        break;
    }
    echo $i;
    $i++;
} 

/* 范例 4 */

for ($i = 1, $j = 0; $i <= 10; $j += $i, print $i, $i++);
?>

当然,第一个例子看上去最正常(或者第四个),但用户可能会发现在   for 循环中用空的表达式在很多场合下会很方便。  

PHP 也支持用冒号的 for 循环的替代语法。

for ( 表达式 1; 表达式 2; 表达式 3 ):
    echo 'xlxz';
endfor;

我们经常需要对下面这样的数组进行遍历:

<?php
/*
 * 我们想要在遍历的过程中改变以下数组中某些元素的值
 */
$xlxz = Array(
        Array('name' => 'Kalle', 'salt' => 856412),
        Array('name' => 'Pierre', 'salt' => 215863)
        ); 

for($i = 0; $i < sizeof($xlxz); ++$i)
{
    $xlxz[$i]['salt'] = rand(000000, 999999);
}
?>

以上代码的问题,在于for的第二个表达式会导致代码执行很慢--因为每次循环时都要 计算一遍数组的长度。由于数组的长度始终不变,我们可以用一个中间变量来存储数组长度, 然后用这个变量作为for循环的第二个表达式。这样在循环的时候就可以直接使用该变量的值, 不用每次重新计算。  如下:

<?php
$xlxz = Array(
        Array('name' => 'Kalle', 'salt' => 856412),
        Array('name' => 'Pierre', 'salt' => 215863)
        ); 

for($i = 0, $size = sizeof($xlxz); $i < $size; ++$i)
{
    $xlxz[$i]['salt'] = rand(000000, 999999);
}
?>

foreach

PHP 4 引入了 foreach 结构,和   Perl 以及其他语言很像。这只是一种遍历数组简便方法。foreach仅能用于数组,当试图将其用于其它数据类型或者一个未初始化的变量时会产生错误。有两种语法,第二种比较次要但却是第一种的有用的扩展。

foreach ( $array as $value)
    statement
foreach ( $array as $key => $value)
    statement

第一种格式遍历给定的 array_expression数组。每次循环中,当前单元的值被赋给 $value并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。  

  第二种格式做同样的事,只除了当前单元的键名也会在每次循环中被赋给变量   $key。  

  自PHP 5 起,还可能遍历对象。

Note:    

foreach开始执行时,数组内部的指针会自动指向第一个单元。这意味着不需要在    foreach 循环之前调用 reset()

Note:    

除非数组是被引用,foreach所操作的是指定数组的一个拷贝,而不是该数组本身。foreach对数组指针有些副作用。除非对其重置,在    foreach 循环中或循环后都不要依赖数组指针的值。

自 PHP 5 起,可以很容易地通过在 $value 之前加上    & 来修改数组的元素。此方法将以引用赋值而不是拷贝一个值。

<?php
$arr = array( 1, 2, 3, 4 );
foreach ($arr as &$value) {
    $value = $value * 2;
}
/* 

    现在数组是  array( 2, 4, 6, 8 )     

*/

?>

Note:    

foreach 不支持用“@”来抑制错误信息的能力。

以下的代码功能完全相同:

<?php
$arr = array("one", "two", "three");
reset($arr);
while (list(, $value) = each($arr)) {
    echo "结果: $value<br>\n";
} 

foreach ($arr as $value) {
    echo "结果: $value<br />\n";
}
?>

以下代码功能也完全相同:

<?php
$arr = array("one", "two", "three");
reset($arr);
while (list($key, $value) = each($arr)) {
    echo "键: $key; 值: $value<br />\n";
} 

foreach ($arr as $key => $value) {
    echo "键: $key; 值: $value<br />\n";
}
?>

更多例子:

<?php
/* foreach 范例 1 */

$a = array(1, 2, 3, 17); 

foreach ($a as $v) {
   echo " 值: $v.\n";
} 

/* foreach  范例 2 */

$a = array(1, 2, 3, 17); 

$i = 0; 

foreach ($a as $v) {
    echo "\$a[$i] => $v.\n";
    $i++;
} 

/* foreach 范例 3: 键 和 值 */

$a = array(
    "one" => 1,
    "two" => 2,
    "three" => 3,
    "seventeen" => 17
); 

foreach ($a as $k => $v) {
    echo "\$a[$k] => $v.\n";
} 

/* foreach 范例 4: 多重循环 */
$a = array();
$a[0][0] = "a";
$a[0][1] = "b";
$a[1][0] = "y";
$a[1][1] = "z"; 

foreach ($a as $v1) {
    foreach ($v1 as $v2) {
        echo "$v2\n";
    }
} 

/* foreach 范例 5: */

foreach (array(1, 2, 3, 4, 5) as $v) {
    echo "$v";
}
?>

break

break 结束当前   forforeachwhiledo-while或者 switch 结构的执行。  

break 可以接受一个可选的  数字  参数来决定跳出几重循环。  

<?php
$arr = array('one', 'two', 'three', 'four', 'stop', 'five');
while (list (, $val) = each($arr)) {
    if ($val == 'stop') {
        break;  // 当然 也可以写成 break 1;
    }
    echo "$val<br />\n";
}  

/* 使用可选参数 */

$i = 0;
while (++$i) {
    switch ($i) {
    case 5:
        echo "At 5<br />\n";
        break 1;  /* 只退出 switch. */
    case 10:
        echo "At 10; quitting<br />\n";
        break 2;  /* 退出 switch 和 while 循环 */
    default:
        break;
    }
}
?>

continue

continue在循环结构用用来跳过本次循环中剩余的代码并在条件求值为真时开始执行下一次循环。  

Note:    注意在 PHP 中    switch语句被认为是可以使用 continue 的一种循环结构。

   continue 接受一个可选的  数字  参数来决定跳过几重循环到循环结尾。  

<?php
while (list ($key, $value) = each($arr)) {
    if (!($key % 2)) {
        continue;
    }
    do_something_odd($value);
} 

$i = 0;
while ($i++ < 5) {
    echo "Outer<br />\n";
    while (1) {
        echo "&nbsp;&nbsp;Middle<br />\n";
        while (1) {
            echo "&nbsp;&nbsp;Inner<br />\n";
            continue 3;
        }
        echo "This never gets output.<br />\n";
    }
    echo "Neither does this.<br />\n";
}
?>

switch

switch 语句和具有同样表达式的一系列的 IF   语句相似。很多场合下需要把同一个变量(或表达式)与很多不同的值比较,并根据它等于哪个值来执行不同的代码。这正是   switch 语句的用途。  

Note:    注意和其它语言不同,continue语句作用到 switch 上的作用类似于 break。如果在循环中有一个    switch 并希望 continue 到外层循环中的下一个轮回,用 continue 2。  

下面两个例子使用两种不同方法实现同样的事,一个用一系列的   if 语句,另一个用 switch 语句:

<?php
if ($i == 0) {
    echo "i 等于 0";
} elseif ($i == 1) {
    echo "i 等于 1";
} elseif ($i == 2) {
    echo "i 等于 2";
} 

switch ($i) {
    case 0:
        echo "i 等于 0";
        break;
    case 1:
        echo "i 等于 1";
        break;
    case 2:
        echo "i 等于 2";
        break;
}
?>

switch 结构可以用字符串

<?php
switch ($i) {
case "apple":
    echo "i 是 apple";
    break;
case "bar":
    echo "i 是 bar";
    break;
case "cake":
    echo "i 是 cake";
    break;
}
?>

为避免错误,理解 switch 是怎样执行的非常重要。switch语句一行接一行地执行(实际上是语句接语句)。开始时没有代码被执行。仅当一个   case 语句中的值和 switch表达式的值匹配时 PHP 才开始执行语句,直到 switch的程序段结束或者遇到第一个 break语句为止。如果不在 case 的语句段最后写上 break的话,PHP 将继续执行下一个 case 中的语句段。例如:

<?php
switch ($i) {
    case 0:
        echo "i 等于 0";
    case 1:
        echo "i
等于
1";
    case 2:
        echo "i
等于
2";
}
?>

这里如果 $i 等于 0,PHP 将执行所有的 print 语句!如果   $i 等于 1,PHP 将执行后面两条 print 语句。只有当   $i 等于 2 时,才会得到“预期”的结果——只显示“i equals 2”。所以,别忘了   break 语句就很重要(即使在某些情况下故意想避免提供它们时)。  

  在 switch 语句中条件只求值一次并用来和每个   case 语句比较。在 elseif语句中条件会再次求值。如果条件比一个简单的比较要复杂得多或者在一个很多次的循环中,那么用   switch 语句可能会快一些。  

  在一个 case 中的语句也可以为空,这样只不过将控制转移到了下一个 case 中的语句。

<?php
switch ($i) {
    case 0:
    case 1:
    case 2:
        echo "i 是 0 或 1 或 2";
        break;
    case 3:
        echo "i 是 3";
}
?>

一个 case 的特例是 default。它匹配了任何和其它   case 都不匹配的情况。例如:

<?php
switch ($i) {
    case 0:
        echo "i 等于 0";
        break;
    case 1:
        echo "i
等于
1";
        break;
    case 2:
        echo "i
等于
2";
        break;
    default:
        echo "i 不是 0, 1 或 2";
}
?>

case表达式可以是任何求值为简单类型的表达式,即整型或浮点数以及字符串。不能用数组或对象,除非它们被解除引用成为简单类型。  

switch 支持替代语法的流程控制。

<?php
switch ($i):
    case 0:
        echo "i
等于
0";
        break;
    case 1:
        echo "i
等于
1";
        break;
    case 2:
        echo "i
等于
2";
        break;
    default:
        echo "
i 不是 0, 1 或 2
";
endswitch;
?>

允许使用分号(;)代替case语句后的冒号(:),例如:

<?php
switch($yanse)
{
    case 'hong';
    case 'lan';
    case 'bai';
        echo 'Good choice';
    break;
    default;
        echo '请选一个颜色...';
    break;
}
?>

declare

declare 结构用来设定一段代码的执行指令。declare的语法和其它流程控制结构相似:  

declare (directive)
    statement

directive 部分允许设定 declare代码段的行为。目前只认识两个指令:ticks(更多信息见下面   ticks 指令)以及    encoding(更多信息见下面 encoding指令)。

Note:         encoding 是 PHP 5.3.0 新增指令。

declare 代码段中的 statement部分将被执行——怎样执行以及执行中有什么副作用出现取决于   directive 中设定的指令。  

declare 结构也可用于全局范围,影响到其后的所有代码(但如果有    declare 结构的文件被其它文件包含,它对包含它的文件不起作用)。  

<?php
// these are the same: 

// you can use this:
declare(ticks=1) {
    // entire script here
} 

// or you can use this:
declare(ticks=1);
// entire script here
?>

Caution

     ticks 指令在 PHP 5.3.0 中是过时指令,将会从 PHP 6.0.0 移除。

Tick 是一个在 declare 代码段中解释器每执行    N 条低级语句就会发生的事件。N的值是在 declare 中的 directive 部分用    ticks=N 来指定的。  

   在每个 tick 中出现的事件是由 register_tick_function()来指定的。更多细节见下面的例子。注意每个 tick 中可以出现多个事件。

<?php
// A function that records the time when it is called
function profile($dump = FALSE)
{
    static $profile; 

    // Return the times stored in profile, then erase it
    if ($dump) {
        $temp = $profile;
        unset($profile);
        return ($temp);
    } 

    $profile[] = microtime();
} 

// Set up a tick handler
register_tick_function("profile"); 

// Initialize the function before the declare block
profile(); 

// Run a block of code, throw a tick every 2nd statement
declare(ticks=2) {
    for ($x = 1; $x < 50; ++$x) {
        echo similar_text(md5($x), md5($x*$x)), "<br />;";
    }
} 

// Display the data stored in the profiler
print_r(profile (TRUE));
?>

这个例子评估“declare”中的 PHP    代码,每执行两条低级语句就记录一次时间。此信息可以用来找到一段特定代码中速度慢的部分。这个过程也可以用其它方法完成,但用    tick 更方便也更容易实现。  

Ticks 很适合用来做调试,以及实现简单的多任务,后台 I/O 和很多其它任务。