语句
一般
语法
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
子句与语法允许的最近的前面if
或elseif
相关联。
示例
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-value 和foreach-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 的字面值应为 0
或 1
。只有无语句形式可用于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