语句

一般

语法

statement:
   compound-statement
   named-label-statement
   expression-statement
   selection-statement
   iteration-statement
   jump-statement
   try-statement
   declare-statement
   echo-statement
   unset-statement
   const-declaration
   function-definition
   class-declaration
   interface-declaration
   trait-declaration
   namespace-definition
   namespace-use-declaration
   global-declaration
   function-static-declaration

复合语句

语法

compound-statement:
   {   statement-listopt   }

statement-list:
   statement
   statement-list   statement

语义

复合语句允许将零个或多个语句在语法上视为单个语句。复合语句通常称为代码块

示例

if (condition)
{ // braces are needed as the true path has more than one statement
  // statement-1
  // statement-2
}
else
{ // braces are optional as the false path has only one statement
  // statement-3
}
// -----------------------------------------
while (condition)
{ // the empty block is equivalent to a null statement
}

带标签的语句

语法

named-label-statement:
   name   :

约束

命名标签在函数内必须唯一。

语义

命名标签可以用作goto 语句的目标。标签的存在本身不会改变执行流程。

表达式语句

语法

expression-statement:
   expressionopt   ;

语义

如果存在,表达式将被评估以获取其副作用(如果有),并且任何生成的返回值将被丢弃。如果表达式被省略,该语句将是一个空语句,它对执行没有影响。

示例

$i = 10;  // $i is assigned the value 10; result (10) is discarded
++$i; // $i is incremented; result (11) is discarded
$i++; // $i is incremented; result (11) is discarded
DoIt(); // function DoIt is called; result (return value) is discarded
// -----------------------------------------
$i;   // no side effects, result is discarded. Vacuous but permitted
123;  // likewise for this one and the two statements following
34.5 * 12.6 + 11.987;
TRUE;
// -----------------------------------------
function findValue($table, $value)  // where $table is 2x3 array
{
  for ($row = 0; $row <= 1; ++$row)
  {
    for ($colm = 0; $colm <= 2; ++$colm)
    {
      if ($table[$row][$colm] == $value)
      {
        // ...
        goto done;
      }
    }
  }
  // ...
done:
  ;     // null statement needed as a label must precede a statement
}

选择语句

一般

语法

selection-statement:
   if-statement
   switch-statement

语义

根据控制表达式的值,选择语句从一组语句中选择一个。

if 语句

语法

if-statement:
   if   (   expression   )   statement   elseif-clauses-1opt   else-clause-1opt
   if   (   expression   )   :   statement-list   elseif-clauses-2opt   else-clause-2opt   endif   ;

elseif-clauses-1:
   elseif-clause-1
   elseif-clauses-1   elseif-clause-1

elseif-clause-1:
   elseif   (   expression   )   statement

else-clause-1:
   else   statement

elseif-clauses-2:
   elseif-clause-2
   elseif-clauses-2   elseif-clause-2

elseif-clause-2:
   elseif   (   expression   )   :   statement-list

else-clause-2:
   else   :   statement-list

语义

if 语句的两种形式是等效的;它们只是提供不同的风格。

控制表达式表达式的结果将在转换为类型bool,如果它没有这种类型。

如果表达式TRUE,则立即执行其后的语句。否则,如果存在elseif 子句,则依次评估其表达式,如果为TRUE,则执行紧随elseif 后的语句。对于每个elseif 子句,依次重复此过程。如果所有这些测试都不为TRUE,则如果存在else 子句,则执行紧随else 后的语句

else 子句与语法允许的最近的前面ifelseif 相关联。

示例

if ($count > 0)
{
  ...
  ...
  ...
}
// -----------------------------------------
goto label1;
echo "Unreachable code\n";

if ($a)
{
label1:
  ...
}
else
{
  ...
}
// -----------------------------------------
if (1)
  ...
  if (0)
    ...
else  // this else does NOT go with the outer if
  ...

if (1)
{
  ...
  if (0)
    ...
}
else  // this else does go with the outer if
    ...

switch 语句

语法

switch-statement:
   switch   (   expression   )   {   case-statementsopt   }
   switch   (   expression   )   :   case-statementsopt   endswitch;

case-statements:
   case-statement   case-statementsopt
   default-statement   case-statementsopt

case-statement:
   case   expression   case-default-label-terminator   statement-listopt

default-statement:
   default   case-default-label-terminator   statement-listopt

case-default-label-terminator:
   :
   ;

约束

最多只能有一个默认标签。

语义

switch 语句的两种形式是等效的;它们只是提供不同的风格。

根据其表达式的值,switch 语句将控制权转移到case 标签,到默认标签(如果存在);或到紧随switch 语句结束后的语句。case 或默认标签只能直接在最接近的封闭switch 语句中访问。

进入switch 语句时,会评估控制表达式,然后使用与== 相同的语义将其与 case 标签表达式的值进行比较(按词法顺序)。如果匹配,则控制权转移到相应 case 标签后面的语句。如果不存在匹配项,则如果存在默认标签,则控制权转移到该标签后面的语句;否则,控制权转移到紧随switch 语句结束后的语句。如果switch 包含多个 case 标签,其值与控制表达式比较相等,则按词法顺序排列的第一个被视为匹配项。

可以将任意数量的语句与任何 case 或默认标签相关联。在该语句集的末尾没有break 语句的情况下,执行将继续进行到任何后面的语句,忽略关联的标签。如果所有 case 和默认情况下都以break 结束,并且不存在重复值的 case 标签,则 case 和默认标签的顺序无关紧要。

Case 标签值可以是运行时表达式,并且兄弟 case 标签的值类型不需要相同。

可以嵌套 switch 语句,在这种情况下,每个switch 都拥有自己的switch 子句集。

示例

$v = 10;
switch ($v)
{
default:
  echo "default case: \$v is $v\n";
  break;    // break ends "group" of default statements
case 20:
  echo "case 20\n";
  break;    // break ends "group" of case 20 statements
case 10:
  echo "case 10\n"; // no break, so execution continues to the next label's "group"
case 30:
  echo "case 30\n"; // no break, but then none is really needed either
}
// -----------------------------------------
$v = 30;
switch ($v)
{
case 30.0:  // <===== this case matches with 30
  echo "case 30.0\n";
  break;
default:
  echo "default case: \$v is $v\n";
  break;
case 30:    // <===== rather than this case matching with 30
  echo "case 30\n";
  break;
}
// -----------------------------------------
switch ($v)
{
case 10 + $b: // non-constant expression
  // ...
case $v < $a:   // non-constant expression
  // ...
// ...
}

迭代语句

一般

语法

iteration-statement:
   while-statement
   do-statement
   for-statement
   foreach-statement

while 语句

语法

while-statement:
   while   (   expression   )   statement
   while   (   expression   )   :   statement-list   endwhile   ;

语义

while 语句的两种形式是等效的;它们只是提供不同的风格。

控制表达式表达式的结果将在转换为类型bool,如果它没有这种类型。

如果表达式测试为TRUE,则立即执行其后的语句,并重复此过程。如果表达式测试为FALSE,则控制权转移到紧随while 语句结束后的位置。循环体执行零次或多次。

示例

$i = 1;
while ($i <= 10):
  echo "$i\t".($i * $i)."\n"; // output a table of squares
  ++$i;
endwhile;
// -----------------------------------------
while (TRUE)
{
  // ...
  if ($done)
    break;  // break out of the while loop
  // ...
}

do 语句

语法

do-statement:
   do   statement   while   (   expression   )   ;

(注意:不存在备用语法)。

约束

控制表达式表达式必须具有类型bool 或可以隐式转换为该类型。

语义

首先,执行语句,然后评估表达式

控制表达式表达式的结果将在转换为类型bool,如果它没有这种类型。

如果该值测试为TRUE,则重复此过程。如果表达式测试为FALSE,则控制权转移到紧随do 语句结束后的位置。循环体语句执行一次或多次。

示例

$i = 1;
do
{
  echo "$i\t".($i * $i)."\n"; // output a table of squares
  ++$i;
}
while ($i <= 10);

for 语句

语法

for-statement:
   for   (   for-initializeropt   ;   for-controlopt   ;   for-end-of-loopopt   )   statement
   for   (   for-initializeropt   ;   for-controlopt   ;   for-end-of-loopopt   )   :   statement-list   endfor   ;

for-initializer:
   for-expression-group

for-control:
   for-expression-group

for-end-of-loop:
   for-expression-group

for-expression-group:
   expression
   for-expression-group   ,   expression

注意:与 C/C++ 不同,PHP 本身不支持逗号运算符。但是,for 语句的语法已经从 C/C++ 的语法扩展而来,以便在此上下文中实现相同的结果。

语义

for 语句的两种形式是等效的;它们只是提供不同的风格。

for-initializer 中的表达式组将被评估一次,从左到右,以获取其副作用。然后,for-control 中的表达式组将被评估,从左到右(除了最右边的表达式,只为获取其副作用),最右边表达式的值为转换为类型bool。如果结果为TRUE,则执行语句,并从左到右评估for-end-of-loop 中的表达式组,以获取其副作用。然后,重复此过程,从for-control 开始。一旦for-control 中最右边的表达式为FALSE,控制权就会转移到紧随for 语句结束后的位置。循环体语句执行零次或多次。

如果省略for-initializer,则在循环处理开始时不执行任何操作。如果省略for-control,则将其视为for-control 是一个值为TRUE 的表达式。如果省略for-end-of-loop,则在每次迭代结束时不执行任何操作。

示例

for ($i = 1; $i <= 10; ++$i)
{
  echo "$i\t".($i * $i)."\n"; // output a table of squares
}
// -----------------------------------------
// omit 1st and 3rd expressions

$i = 1;
for (; $i <= 10;):
  echo "$i\t".($i * $i)."\n"; // output a table of squares
  ++$i;
endfor;
// -----------------------------------------
// omit all 3 expressions

$i = 1;
for (;;)
{
  if ($i > 10)
    break;
  echo "$i\t".($i * $i)."\n"; // output a table of squares
  ++$i;
}
// -----------------------------------------
//  use groups of expressions

for ($a = 100, $i = 1; ++$i, $i <= 10; ++$i, $a -= 10)
{
  echo "$i\t$a\n";
}

foreach 语句

语法

foreach-statement:
   foreach   (   foreach-collection-name   as   foreach-keyopt   foreach-value   )   statement
   foreach   (   foreach-collection-name   as   foreach-keyopt   foreach-value   )   :   statement-list   endforeach   ;

foreach-collection-name:
   expression

foreach-key:
   expression   =>

foreach-value:
   &opt   expression
   list-intrinsic

约束

foreach-collection-name 表达式的结果必须是一个集合,即实现Traversable 的数组或对象。

foreach-valueforeach-key 中的表达式应指定一个变量。

语义

foreach 语句的两种形式是等效的;它们只是提供不同的风格。

foreach 语句遍历foreach-collection-name 指定的集合中的元素集,从开头开始,每次迭代执行语句。在每次迭代中,如果foreach-value 中存在&,则将由相应表达式指定的变量设为当前元素的别名。如果省略了&,则将当前元素的值分配给相应的变量。循环体语句执行零次或多次。循环终止后,foreach-value表达式指定的变量将具有与最终迭代(如果有)后相同的的值。

如果存在foreach-key,则将由其表达式指定的变量分配当前元素的键值。

list-intrinsic 案例中,数组值将拆分为单个元素。

示例

$colors = array("red", "white", "blue");
foreach ($colors as $color):
    // ...
endforeach;
// -----------------------------------------
foreach ($colors as $key => $color)
{
    // ...
}
// -----------------------------------------
// Modify the local copy of an element's value

foreach ($colors as $color)
{
  $color = "black";
}
// -----------------------------------------
// Modify the the actual element itself

foreach ($colors as &$color)  // note the &
{
  $color = "black";
}

跳转语句

一般

语法

jump-statement:
   goto-statement
   continue-statement
   break-statement
   return-statement
   throw-statement

goto 语句

语法

goto-statement:
   goto   name   ;

约束

goto 语句中的名称必须是当前脚本中某个位置的命名标签。控制权不能转移到函数内或函数外,也不能转移到迭代语句switch 语句 中。

goto 语句不能尝试从finally 代码块 中转移控制权。

语义

goto 语句将控制权无条件地转移到命名标签

goto 语句可以从完全包含在finally 代码块 中的结构中跳出。

示例

function findValue($table, $v)  // where $table is 2x3 array
{
  for ($row = 0; $row <= 1; ++$row)
  {
    for ($colm = 0; $colm <= 2; ++$colm)
    {
      if ($table[$row][$colm] == $v)
      {
        echo "$v was found at row $row, column $colm\n";
        goto done; // not quite the same as break 2!
      }
    }
  }
  echo "$v was not found\n";
done:
  ; // note that a label must always precede a statement
}

continue 语句

语法

continue-statement:
   continue   breakout-levelopt   ;

breakout-level:
   integer-literal
   (   breakout-level   )

约束

跳出级别必须大于零,并且不能超过实际封闭迭代和/或switch 语句的级别。

continue 语句不能尝试从finally 代码块 中跳出。

语义

continue 语句终止最内层封闭迭代switch 语句的执行。breakout-level 指定哪个语句是目标,最内层的语句被分配数字1,包含的语句的级别递增 1。

continue 语句终止一个或多个封闭迭代switch 语句的执行,直到指定的级别。如果breakout-level 指定的语句是迭代语句,则将开始迭代语句的下一个迭代(如果有)。如果该语句是for 语句,并且它具有for-end-of-loop,则首先会评估当前迭代的 end-of-loop 表达式组。如果它是switch 语句,则会发出警告,并且行为与同一breakout-level 上的break 语句 相同。如果省略了breakout-level,则假定为 1 级。

continue 语句可以从完全包含在 finally 代码块中的结构中跳出。

示例

for ($i = 1; $i <= 5; ++$i)
{
  if (($i % 2) == 0)
    continue;
  echo "$i is odd\n";
}

break 语句

语法

break-statement:
   break   breakout-levelopt   ;

约束

跳出级别必须大于零,并且不能超过实际封闭迭代和/或switch 语句的级别。

break 语句不能尝试从finally 代码块 中跳出。

语义

break 语句终止一个或多个封闭迭代 或[]switch](#the-switch-statement) 语句的执行。跳出级别由breakout-level 指定。如果省略了breakout-level,则假定为 1 级。

break 语句可以从完全包含在 finally 代码块中的结构中跳出。

示例

$i = 1;
for (;;)
{
  if ($i > 10)
    break;
  // ...
  ++$i;
}
// -----------------------------------------
for ($row = 0; $row <= 1; ++$row)
{
  for ($colm = 0; $colm <= 2; ++$colm)
  {
    if (some-condition-set)
    {
      break 2;
    }
    // ...
  }
}
// -----------------------------------------
for ($i = 10; $i <= 40; $i +=10)
{
        switch($i)
        {
        case 10: /* ... */; break;    // breaks to the end of the switch
        case 20: /* ... */; break 2;  // breaks to the end of the for
        case 30: /* ... */; break;    // breaks to the end of the switch
        }
}

return 语句

语法

return-statement:
   return   expressionopt   ;

语义

函数内的return 语句会正常终止该函数的执行,并根据函数的定义方式,通过值或通过引用将表达式的值返回给函数的调用方。如果省略了表达式,则使用值NULL

如果执行流程进入函数的闭合花括号 (}),则隐式执行 return NULL;

在具有 void 返回类型 的函数中,不允许使用带有表达式的显式 return 语句,这会导致致命错误。

函数可以包含任意数量的 return 语句,其返回值类型可以不同。

如果通过引用返回未定义的变量,则该变量将被定义,其值为 NULL

return 语句可以在 try 块catch 块finally 块 中使用。

在 finally 块中使用 return 语句将覆盖 try 块及其所有 catch 块中的任何其他 return 语句或抛出的异常。父级堆栈中的代码执行将继续,就好像从未抛出异常一样。

如果在执行 finally 块时存在未捕获的异常,并且该 finally 块执行 return 语句,则未捕获的异常将被丢弃。

return 语句可以出现在任何函数之外的脚本中。在 包含的文件 中,此类语句将终止对该脚本文件的处理,并将控制权返回给包含文件。如果存在表达式,则该表达式为返回的值;否则,返回的值为 NULL。如果执行流程流到脚本的末尾,则隐式执行 return 1;。但是,如果执行流程流到脚本顶层的末尾,则隐式执行 return 0;。同样,如果在顶层省略表达式。(另请参见 exit).

从构造函数或析构函数中返回的行为与从函数中返回的行为相同。

return 语句出现在 生成器函数 中会导致生成器终止。

生成器函数可以包含 return 表达式 ; 形式的语句。可以使用 Generator::getReturn 方法获取此返回的值,该方法只能在生成器完成生成值后才能调用。该值不能通过引用返回。

返回语句也可以用于匿名函数的函数体中。

return 也会终止传递给内部 eval 的源代码的执行。

示例

function f() { return 100; }  // f explicitly returns a value
function g() { return; }   // g explicitly returns an implicit NULL
function h() { }      // h implicitly returns NULL
// -----------------------------------------
// j returns one of three dissimilarly-typed values
function j($x)
{
  if ($x > 0)
  {
    return "Positive";
  }
  else if ($x < 0)
  {
    return -1;
  }
  // for zero, implied return NULL
}
function &compute() { ...; return $value; } // returns $value byRef
// -----------------------------------------
class Point
{
  private static $pointCount = 0;
  public static function getPointCount()
  {
    return self::$pointCount;
  }
  ...
}

实现说明

虽然表达式完整的表达式,并且在该表达式的末尾有一个 顺序点,但如果可以确定没有其他程序代码依赖于其发生,则不需要执行副作用。(例如,在 return $a++;return ++$a; 的情况下,很明显在每种情况下必须返回什么值,但如果 $a 是封闭函数的局部变量,则 $a 实际上不需要递增。

throw 语句

语法

throw-statement:
   throw   expression   ;

约束

表达式的类型必须为 Exception 或该类的子类。

表达式必须能够创建对其的别名。

语义

throw 语句会立即且无条件地抛出异常。控制权永远不会到达紧跟在 throw 之后的语句。有关抛出和捕获异常以及如何处理未捕获异常的更多详细信息,请参见 异常处理try 语句

catch 块可以(重新)抛出与其捕获的异常相同的异常,也可以抛出不同类型的异常,而不是处理异常。

示例

throw new Exception;
throw new Exception("Some message", 123);
class MyException extends Exception { ... }
throw new MyException;

try 语句

语法

try-statement:
   try   compound-statement   catch-clauses
   try   compound-statement   finally-clause
   try   compound-statement   catch-clauses   finally-clause

catch-clauses:
   catch-clause
   catch-clauses   catch-clause

catch-clause:
   catch   (   catch-name-list   variable-name   )   compound-statement

catch-name-list:
   qualified-name
   catch-name-list   |   qualified-name

finally-clause:
   finally   compound-statement

约束

catch-name-list 中的每个限定名必须命名从 Exception 派生的类型。

语义

catch 子句中,变量名指定按值传递的异常变量。此变量对应于作用域扩展到 catch 块的局部变量。在执行 catch 块期间,异常变量表示当前正在处理的异常。

抛出异常后,引擎会搜索最靠近的可以处理该异常的 catch 块。该过程从当前函数级别开始,搜索词汇上包含抛出点的 try 块。按词汇顺序考虑与该 try 块关联的所有 catch 块。如果找不到可以处理异常的运行时类型的 catch 块,则搜索调用当前函数的函数,以查找词汇上包含对当前函数的调用的 try 块。此过程会一直持续,直到找到可以处理当前异常的 catch 块为止。

匹配是通过考虑catch-name-list限定名指定的类,并将其与异常的类型进行比较来完成的。如果异常是 指定的类之一的实例,则该子句匹配。

如果找到匹配的 catch 块,则引擎会准备将控制权转移到该 catch 块的第一条语句。但是,在执行该 catch 块之前,引擎首先按顺序执行与比捕获异常的 try 块更深层嵌套的 try 块关联的所有 finally 块。

如果找不到匹配的 catch 块,则异常将未捕获,行为将由实现定义。

示例

function getTextLines($filename)
{
  $infile = fopen($filename, 'r');
  if ($infile == FALSE) { /* deal with an file-open failure */ }
  try
  {
    while ($textLine = fgets($infile))  // while not EOF
    {
      yield $textLine;  // leave line terminator attached
    }
  }
  finally
  {
    fclose($infile);
  }
}
// -----------------------------------------
class DeviceException extends Exception { ... }
class DiskException extends DeviceException { ... }
class RemovableDiskException extends DiskException { ... }
class FloppyDiskException extends RemovableDiskException { ... }

try
{
  process(); // call a function that might generate a disk-related exception
}
catch (FloppyDiskException $fde) { ... }
catch (RemovableDiskException $rde) { ... }
catch (DiskException $de) { ... }
catch (DeviceException $dve) { ... }
finally { ... }

declare 语句

语法

declare-statement:
   declare   (   declare-directive   )   statement
   declare   (   declare-directive   )   :   statement-list   enddeclare   ;
   declare   (   declare-directive   )   ;

declare-directive:
   ticks   =   literal
   encoding   =   literal
   strict_types   =   literal

约束

ticks 的字面值必须指定一个值,该值是或可以转换为具有非负值的整数。

encoding 的字面值必须指定一个字符串,其值为 8 位 字符编码 的名称。

除了空格之外,指定字符编码的脚本中的declare 语句必须是该脚本中的第一项。

strict_types 的字面值应为 01。只有无语句形式可用于strict_types 声明。strict_types 声明应是脚本中的第一条语句,除了其他 declare 语句。

语义

declare 语句的前两种形式是等效的;它们只是提供不同的样式。

declare 语句为其语句主体设置执行指令,或者对于 ; 形式,为脚本的其余部分设置执行指令,直到语句被另一个declare 语句覆盖,以先发生者为准。

ticks:在解析器执行期间,某些语句被认为是可计时的。每 tick-count 个计时,都会发生一个事件,该事件可以由以前通过库函数 register_tick_function 注册的函数进行处理。可以通过调用库函数 unregister_tick_function 禁用计时事件监控。此功能允许开发分析机制。

encoding:可以使用 encoding 指令在脚本级别指定字符编码。联合 ISO 和 IEC 标准 ISO/IEC 8859 标准系列 指定了许多 8 位 字符编码,可以使用此指令使用这些编码的名称。此指令仅适用于它所在的代码文件,不影响包含的文件。

strict_types:如果设置为 1,则使用 严格模式 检查函数调用的标量类型检查。如果设置为 0,则使用强制模式(默认模式)。此指令仅适用于它所在的代码文件,不影响包含的文件。

示例

declare(ticks = 1) { ... }
declare(encoding = 'ISO-8859-1'); // Latin-1 Western European
declare(encoding = 'ISO-8859-5'); // Latin/Cyrillic

echo 语句

语法

echo-statement:
   echo   expression-list   ;

expression-list:
   expression
   expression-list   ,   expression

约束

表达式的值必须 可转换为字符串。特别是,它不应该是一个数组,如果它是一个对象,则它必须实现 __toString 方法

语义

echo 在必要时将每个表达式的值转换为字符串,然后按给定的顺序连接它们,并将生成的字符串写入 STDOUT。与 print 不同,它不会产生结果。

另请参见:双引号字符串heredoc 文档转换为字符串

示例

$v1 = TRUE;
$v2 = 123;
echo  '>>' . $v1 . '|' . $v2 . "<<\n";    // outputs ">>1|123<<"
echo  '>>' , $v1 , '|' , $v2 , "<<\n";    // outputs ">>1|123<<"
echo ('>>' . $v1 . '|' . $v2 . "<<\n");   // outputs ">>1|123<<"
$v3 = "qqq{$v2}zzz";
echo "$v3\n";

unset 语句

语法

unset-statement:
   unset   (   variable-list   ,opt   )   ;

语义

此语句 取消设置 变量列表 中每个变量指定的变量。没有返回值。尝试取消设置不存在的变量(例如数组中不存在的元素)将被忽略。

当从函数内部调用时,此语句的行为如下:

  • 对于在该函数中声明为 global 的变量,unset 会从对该函数的当前调用的作用域中删除对该变量的别名。全局变量将保持设置。(要取消设置全局变量,请对相应的 $GLOBALS 数组条目使用 unset。
  • 对于通过引用传递给该函数的变量,unset 会从对该函数的当前调用的作用域中删除对该变量的别名。函数返回后,传入的参数变量仍然被设置。
  • 对于在该函数中声明为 static 的变量,unset 会从对该函数的当前调用的作用域中删除对该变量的别名。在对该函数的后续调用中,static 变量仍然被设置,并保留其从调用到调用的值。

任何可见的实例属性都可以取消设置,在这种情况下,该属性将从该实例中删除。

如果此语句与指定 动态属性 的表达式一起使用,那么如果该属性的类具有 __unset 方法,则会调用该方法。

示例

unset($v);
unset($v1, $v2, $v3);
unset($x->m); // if m is a dynamic property, $x->__unset("m") is called