(这比我打算的要长;请耐心等待。)
大多数语言由一种称为“语法”的东西组成:该语言由几个定义明确的关键字组成,并且您可以用该语言构造的完整表达范围都是由该语法建立的。
例如,假设您有一个简单的四功能算术“语言”,它仅将一位整数作为输入,而完全忽略了运算顺序(我告诉过您这是一种简单的语言)。该语言可以通过以下语法定义:
// The | means "or" and the := represents deFinition
$expression := $number | $expression $operator $expression
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
$operator := + | - | * | /
根据这三个规则,您可以构建任意数量的一位数字输入算术表达式。然后,您可以编写一个解析器这句法,打破了任何有效的投入到它的组件类型($expression
,$number
或$operator
)并处理结果。例如,3 + 4 * 5
可以将表达式分解如下:
// Parentheses used for ease of explanation; they have no true syntactical meaning
$expression = 3 + 4 * 5
= $expression $operator (4 * 5) // Expand into $exp $op $exp
= $number $operator $expression // Rewrite: $exp -> $num
= $number $operator $expression $operator $expression // Expand again
= $number $operator $number $operator $number // Rewrite again
现在,我们可以使用定义的语言对原始表达式进行完全解析的语法。一旦有了这个,我们就可以编写一个解析器来查找的所有组合的结果$number $operator $number
,并在只剩下一个时吐出一个结果$number
。
请注意,$expression
原始表达式的最终解析版本中没有剩余的构造。这是因为$expression
在我们的语言中,总可以归结为其他事物的组合。
PHP大致相同:语言构造被认为与我们的$number
or 等效$operator
。它们 ; 相反,它们是构建语言的基础单元。函数和语言构造之间的主要区别在于:解析器直接处理语言构造。它将功能简化为语言结构。
语言构造可能需要或可能不需要括号的原因,以及某些具有返回值而另一些却没有返回值的原因完全取决于PHP解析器实现的特定技术细节。我对解析器的工作原理不甚了解,因此我无法具体解决这些问题,但请想象一下以此开头的语言:
$expression := ($expression) | ...
实际上,该语言可以自由地使用它找到的任何表达式并摆脱周围的括号。PHP(这里我使用纯粹的猜测方法)对其语言结构可能采用类似的方式:print("Hello")
可能会简化为print "Hello"
解析之前的语言,反之亦然(语言定义既可以添加括号也可以删除括号)。
这就是为什么您不能重新定义诸如echo
或的语言构造的根源print
:它们已经有效地硬编码到了解析器中,而函数却映射到了一组语言构造,并且解析器允许您在编译时或运行时将其映射更改为替换您自己的一组语言构造或表达式。
归根结底,构造和表达式之间的内部差异是:解析器可以理解和处理语言构造。内置函数由语言提供,但在解析之前会映射并简化为一组语言结构。
更多信息:
通读一些其他答案,人们会指出自己的观点。其中: