09 语法结构
脚本
[脚本](04-基本概念.html#program-structure)是一个有序的字符序列。通常, 脚本与文件系统中的文件是一一对应关系,但是这种对应不是必需的。
从概念上讲,使用以下步骤翻译脚本:
转换,转换从特定字符的脚本汇编和编码方案转换为8位字符序列。
词汇分析,将输入字符流转换成一个令牌流。
语法分析,将令牌流转换成可执行代码。
一致性实现必须接受使用UTF-8编码的脚本编码形式(由Unicode标准定义),并对它们进行变换 转换为字符序列。实现可以选择接受和变换附加字符编码方案。
语法
本规范显示了使用两个语法的PHP编程语言的语法。词法语法定义源字符如何组合以形成空格,注释和令牌。语法语法定义了所得到的令牌如何组合以形成PHP程序。
使用语法生成来呈现语法,每个语法定义非终端符号和该非终端符号可能扩展成非终端或终端符号的序列。在制作中,非终端符号以这样的倾斜类型示出,并且终端符号以这样的固定宽度字体示出。
语法生产的第一行是定义的非终端符号的名称,后面是用于语法语法生成的一个冒号,以及用于词法语法生成的两个冒号。每个相继的缩进线包含作为非终端或终端符号序列给出的非终端的可能扩展。例如,生产:
single-line-comment-example:: // input-charactersopt # input-charactersopt
将词法语法生产单行注释定义为终端//
或#
,后跟可选的输入字符。 每个扩展单独列出。
尽管替换方案通常在单独的行上列出,但是当存在大数量时,简写短语“一个”可以在单个行上给出的扩展列表之前。 例如,
hexadecimal-digit-example:: one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
词法分析
概述
生产输入文件是脚本的词法结构的根本。 每个脚本必须符合此生产。
语法
input-file:: input-element input-file input-element input-element:: comment white-space token
语义
脚本的基本元素是注释,空格和符号。
脚本的词法处理涉及减少该脚本 成为成为输入的tokens序列 句法分析。 令牌可以由[空格](#white-space)和 delimited comments。
词法处理总是导致创建最长的 可能的词汇元素。 (例如,$a+++++$b
必须解析为 $a++ ++ +$b
,在语法上无效)。
注释
支持两种形式的注释:分隔注释和单行注释。
语法
comment:: single-line-comment delimited-comment single-line-comment:: // input-charactersopt # input-charactersopt input-characters:: input-character input-characters input-character input-character:: Any source character except new-line new-line:: Carriage-return character (U+000D) Line-feed character (U+000A) Carriage-return character (U+000D) followed by line-feed character (U+000A) delimited-comment:: /* No characters or any source character sequence except */ */
语义
除了在字符串文字或注释中,字符/*
开始以分隔符注释,以字符*/
结束。 除了在字符串文字或注释中,字符//
或#
开始单行注释,以一行结束。 那个新行不是评论的一部分。 但是,如果单行注释是嵌入脚本中的最后一个 源元素,则可以省略结尾的新行。 (注意:这允许使用<?php ... // ...?>
)。
分隔的注释可以发生在可能出现空格的脚本中的任何位置。 (例如;/*...*/$c/*...*/=/*...*/567/*...*/;/*...*/
被解析成 $c=567;
, $k = $i+++/*...*/++$j;
被解析成 $k = $i+++ ++$j;
).
实现注意事项
在标记化期间,实现可以将分隔的注释看作是空白。
空格
空格由一个或多个的任意组合组成新行,空格和水平制表符。
语法
white-space:: white-space-character white-space white-space-character white-space-character:: new-line Space character (U+0020) Horizontal-tab character (U+0009)
语义
空格和水平制表符视为水平空格字符。
符号
概述
有几种源符号:
语法
token:: variable-name name keyword integer-literal floating-literal string-literal operator-or-punctuator
名称
语法
variable-name:: $ name namespace-name:: name namespace-name \ name namespace-name-as-a-prefix:: \ \opt namespace-name \ namespace \ namespace \ namespace-name \ qualified-name:: namespace-name-as-a-prefixopt name name:: name-nondigit name name-nondigit name digit name-nondigit:: nondigit one of the characters U+0080–U+00ff nondigit:: one of _ a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
语义
名称用于标识以下内容:常量,变量, 标签,函数, 类,类成员, 接口,traits, 命名空间和heredoc和nowdoc注释中的名称。
名称以下划线(_),名称无引号或扩展名称字符开头,范围为U+0080–-U+00ff。后续字符也可以包括数字。变量名是带有前导美元($)的名称。
除非另有说明(函数,类,方法,接口,traits,命名空间),名称区分大小写,并且名称中的每个字符都是重要的。
以两个下划线(__)开头的名称由PHP语言保留,不应由用户代码定义。
以下名称不能用作类,接口或traits的名称:bool
,FALSE
,float
,int
,NULL
,string
,TRUE
,iterable
和void
。
以下名称保留供将来使用,不应用作类,接口或traits的名称:mixed
, numeric
, object
, and resource
。
除了class
之外,所有关键字都可以用作类,接口或trait的成员的名称。但是,class
可以用作属性或方法的名称。
变量名和函数名(当在函数调用上下文中使用时)不需要定义为源令牌; 他们也可以在创建 运行时使用简单变量表达式. (例如, 给出$a = "Total"; $b = 3; $c = $b + 5;
, ${$a.$b.$c} = TRUE;
相当于 $Total38 = TRUE;
, ${$a.$b.$c}()
相当于 Total38()
).
例子
const MAX_VALUE = 100;
function getData() { /*...*/ }
class Point { /*...*/ }
interface ICollection { /*...*/ }
注意事项
不建议使用对名称长度的任意限制。
关键字
关键字是保留的名称类字符序列,并且不能用作名称。
语法
keyword:: one of abstract and array as break callable case catch class clone const continue declare default die do echo else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval exit extends final finally for foreach function global goto if implements include include_once instanceof insteadof interface isset list namespace new or print private protected public require require_once return static switch throw trait try unset use var while xor yield yield from
语义
关键字不区分大小写。
注意,yield from
是一个包含空格的单个符号。 但是,在空格中不允许注释。
此外,所有魔术常量也被视为关键字。
语法
代表一个值的源代码被称作文本。文本翻译参考
整型文本
语法
integer-literal:: decimal-literal octal-literal hexadecimal-literal binary-literal decimal-literal:: nonzero-digit decimal-literal digit octal-literal:: 0 octal-literal octal-digit hexadecimal-literal:: hexadecimal-prefix hexadecimal-digit hexadecimal-literal hexadecimal-digit hexadecimal-prefix:: one of 0x 0X binary-literal:: binary-prefix binary-digit binary-literal binary-digit binary-prefix:: one of 0b 0B digit:: one of 0 1 2 3 4 5 6 7 8 9 nonzero-digit:: one of 1 2 3 4 5 6 7 8 9 octal-digit:: one of 0 1 2 3 4 5 6 7 hexadecimal-digit:: one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F binary-digit:: one of 0 1
语义
使用基数10计算十进制整数文本的值; 那 的八进制整数文本,基数是8; 十六进制整数 文本,基数是16; 二进制整数文本,基数是2。
如果由整数文本表示的值可以适合int类型, 这将是结果值的类型; 否则,类型将是float, 如下所述。
因为负数在PHP中表示为正数的相反数字,最小的负值(32位的-2147483648和64位的-9223372036854775808) 不能表示为十进制整数文本。 如果是非负数 值太大,而不能表示为一个int
,它将变成float
,然后加上负号。
使用十六进制,八进制或二进制符号写的文本被认为具有非负值。
整数文本通常是常量表达式。
An integer literal is always a constant expression.
例子
$count = 10; // decimal 10
0b101010 >> 4; // binary 101010 and decimal 4
0XAF << 023; // hexadecimal AF and octal 23
一个使用32位整代表的实现
2147483648 -> 2147483648 (too big for int, so is a float)
-2147483648 -> -2147483648 (too big for int, so is a float, negated)
-2147483647 - 1 -> -2147483648 fits in int
0x80000000 -> 2147483648 (too big for int, so is a float)
浮点型文本
语法
floating-literal:: fractional-literal exponent-partopt digit-sequence exponent-part fractional-literal:: digit-sequenceopt . digit-sequence digit-sequence . exponent-part:: e signopt digit-sequence E signopt digit-sequence sign:: one of + - digit-sequence:: digit digit-sequence digit
约束
浮点文本的值必须可以通过其类型表示。
语义
浮点文本
的类型是float
。
浮点数文本总是一个常量表达式。
例子
$values = array(1.23, 3e12, 543.678E-23);
字符串文本
语法
string-literal:: single-quoted-string-literal double-quoted-string-literal heredoc-string-literal nowdoc-string-literal
语义
字符串文本是以某种方式分隔的零个或多个字符的序列。 分隔符不是文字内容的一部分。
字符串文本的类型是string
。
单引号字符串文本
语法
single-quoted-string-literal:: b-prefixopt ' sq-char-sequenceopt ' sq-char-sequence:: sq-char sq-char-sequence sq-char sq-char:: sq-escape-sequence \opt any member of the source character set except single-quote (') or backslash (\) sq-escape-sequence:: one of \' \\ b-prefix:: one of b B
语义
A single-quoted string literal is a string literal delimited by single-quotes ('
, U+0027). The literal can contain any source character except single-quote ('
) and backslash (\\
), which can only be represented by their corresponding escape sequence.
The optional b-prefix is reserved for future use in dealing with so-called binary strings. For now, a single-quoted-string-literal with a b-prefix is equivalent to one without.
单引号字符串文本是由单引号(', U+0027)分隔的字符串文字。 文本可以包含除单引号(')和反斜杠(\)之外的任何源字符,只能由其相应的转义序列表示。
可选的b-prefix
保留以供将来在处理所谓的二进制字符串时使用。 现在,带有b-prefix
的单引号字符串文本相当于没有。
单引号字符串文本通常是一个常量表达式。
例子
'This text is taken verbatim'
'Can embed a single quote (\') and a backslash (\\) like this'
双引号字符串文本
语法
double-quoted-string-literal:: b-prefixopt " dq-char-sequenceopt " dq-char-sequence:: dq-char dq-char-sequence dq-char dq-char:: dq-escape-sequence any member of the source character set except double-quote (") or backslash (\) \ any member of the source character set except "\$efnrtvxX or octal-digit dq-escape-sequence:: dq-simple-escape-sequence dq-octal-escape-sequence dq-hexadecimal-escape-sequence dq-unicode-escape-sequence dq-simple-escape-sequence:: one of \" \\ \$ \e \f \n \r \t \v dq-octal-escape-sequence:: \ octal-digit \ octal-digit octal-digit \ octal-digit octal-digit octal-digit dq-hexadecimal-escape-sequence:: \x hexadecimal-digit hexadecimal-digitopt \X hexadecimal-digit hexadecimal-digitopt dq-unicode-escape-sequence:: \u{ codepoint-digits } codepoint-digits:: hexadecimal-digit hexadecimal-digit codepoint-digits
语义
双引号字符串文本是由分隔的字符串文本 双引号("
,U+0022)。除了文本可以包含任何源字符 双引号('"')和反斜杠(\\
),它们只能用表示 它们相应的转义序列。 某些其他(有时 不可打印)字符也可以表示为转义序列。
可选的b-prefix保留以供将来使用 所谓的二进制字符串。 现在,一个带有b-prefix前缀的 双引号字符串文字相当于没有这个前缀。
如所描述的,转义序列表示单字符编码 在下表中:
Escape sequence | Character name | Unicode character |
---|---|---|
$ | Dollar sign | U+0024 |
\" | Double quote | U+0022 |
\ | Backslash | U+005C |
\e | Escape | U+001B |
\f | Form feed | U+000C |
\n | New line | U+000A |
\r | Carriage Return | U+000D |
\t | Horizontal Tab | U+0009 |
\v | Vertical Tab | U+000B |
\ooo | 1–3-digit octal digit value ooo | |
\xhh or \Xhh | 1–2-digit hexadecimal digit value hh | |
\u{xxxxxx} | UTF-8 encoding of Unicode codepoint U+xxxxxx | U+xxxxxx |
在双引号字符串文本中,除非被识别为转义序列的开始,否则反斜杠(\)将逐个保留。
在双引号字符串文本中,不使用反斜杠(\)转义的美元($)字符使用下面描述的变量替换规则处理。
\u{xxxxxx}
转义序列使用大括号中指定的十六进制数字生成Unicode代码点的UTF-8编码。 实现不允许超出 U+10FFFF 的 Unicode 代码点,因为这超出了UTF-8可以编码的范围(参见RFC 3629)。 如果指定大于 U+10FFFF 的码点,则实现必须出错。实现必须通过\u
逐字,如果没有后面跟一个开始{
,但是如果是, 实现必须产生一个错误,如果没有终止}
或内容不是有效的代码点,不解释它作为一个转义序列。 实现必须支持前导零,但不能支持开头和结尾括号之间的代码点的前导或尾随空格。实现必须 允许不是Unicode标量值的Unicode代码点,例如高和低代理。
无法通过变量替换创建Unicode转义序列。例如,给定$v = "41"
,"\u{$v}"
将生成 "\u41"
, 长度为4的字符串,而"\u{0$v}"
和"\u{{$v}}"
包含不合格的Unicode转义序列。
变量替换
变量替换遵循以下语法:
string-variable:: variable-name offset-or-propertyopt ${ expression } offset-or-property:: offset-in-string property-in-string offset-in-string:: [ name ] [ variable-name ] [ integer-literal ] property-in-string:: -> name
表达式的工作方式与简单变量表达式的工作方式相同。
在评估由上述语法定义的变量后,根据字符串转换规则将其值 转换为字符串,并将其值代入变量替换表达式中的字符串。
由字符串中的偏移量和字符串中的属性定义的下标或属性访问分别根据下标运算符 和成员访问运算符的规则来解析。例外是, 在字符串内的偏移量被解释为一个字符串文本,即使它没有引号。
如果$
后的字符序列不作为名称解析,并且不以{
开头,则$
字符将逐字地解释,并且不执行变量替换。
变量替代也为表达式的评估提供有限的支持。这是通过在一对匹配 大括号({...}
)中包含一个表达式来实现的。开头的大括号必须紧跟一个美元($
), 没有任何中间的空格,并且美元必须开始一个变量名。如果不是这样,大括号是逐字 处理的。如果大括号({
)被转义,它不会被解释为嵌入表达式的开始,而是逐字解释。
表达式的值根据字符串转换规则转换 为字符串,并替换为代替替换表达式的字符串。
双引号字符串文字是一个常量表达式,如果它不包含任何变量替换。
例子
$x = 123;
echo ">\$x.$x"."<"; // → >$x.123<
// -----------------------------------------
$colors = array("red", "white", "blue");
$index = 2;
echo "\$colors[$index] contains >$colors[$index]<\n";
// → $colors[2] contains >blue<
// -----------------------------------------
class C {
public $p1 = 2;
}
$myC = new C();
echo "\$myC->p1 = >$myC->p1<\n"; // → $myC->p1 = >2<
Heredoc 字符串文本
语法
heredoc-string-literal:: b-prefixopt <<< hd-start-identifier new-line hd-bodyopt hd-end-identifier ;opt new-line hd-start-identifier:: name " name " hd-end-identifier:: name hd-body:: hd-char-sequenceopt new-line hd-char-sequence:: hd-char hd-char-sequence hd-char hd-char:: hd-escape-sequence any member of the source character set except backslash (\) \ any member of the source character set except \$efnrtvxX or octal-digit hd-escape-sequence:: hd-simple-escape-sequence dq-octal-escape-sequence dq-hexadecimal-escape-sequence dq-unicode-escape-sequence hd-simple-escape-sequence:: one of \\ \$ \e \f \n \r \t \v
约束
开始和结束标识符名称必须相同。 在<<<
和起始标识符之间只允许水平空格。 在开始标识符和后面的新行之间不允许有空格。 在新行和后面的结束标识符之间 不允许有空格。 除了可选的分号(;
)之外,在结束标识符和终止该源行的新行之间 不允许有字符 -- 甚至不包括注释或空格。
语义
heredoc字符串文本是由"<<< name
"和"name
"分隔的字符串文字。 文字可以包含任何源字符。 某些其他(有时不可打印)字符也可以表示为转义序列。
heredoc字符串文本支持对双引号字符串文本定义的变量替换。
heredoc字符串文本是一个常量表达式,如果它不包含任何变量替换。
可选的b-prefix没有效果。
例子
$v = 123;
$s = <<< ID
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<";
// → >S'o'me "\"t e xt; $v = 123"
// Some more text<
Nowdoc 字符串文本
语法
nowdoc-string-literal:: b-prefixopt <<< ' name ' new-line hd-bodyopt name ;opt new-line
约束
开始和结束标识符名称必须相同。 在开始标识符名称及其包含的单引号('
)之间不允许有空格。 另请参见heredoc字符串文本。
语义
一个nowdoc字符串文本看起来像一个heredoc字符串文本,除了在前者 开始标识符名称用单引号('
)括起来。 字符串文本的两种形式具有 相同的语义和约束,除了nowdoc字符串文本不受变量替换(如单引号字符串)。
nowdoc字符串文本是一个常量表达式。
可选的b-prefix没有效果。
例子
$v = 123;
$s = <<< 'ID'
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<\n\n";
// → >S'o'me "\"t e\txt; \$v = $v"
// Some more text<
操作符与标点符号
语法
operator-or-punctuator:: one of [ ] ( ) { } . -> ++ -- ** * + - ~ ! $ / % << >> < > <= >= == === != !== ^ | & && || ? : ; = **= *= /= %= += -= .= <<= >>= &= ^= |= , ?? <=> ... \
语义
操作符和标点符号是具有独立语法和语义意义的符号。 在表达式中 使用运算符来描述涉及一个或多个操作对象的操作,并产生结果值, 产生副作用或其某种组合。 标点符号用于分组和分离。