93

我知道 , include, isset, require,printecho其他一些不是函数而是语言结构。

其中一些语言结构需要括号,而另一些则不需要。

require 'file.php';
isset($x);

有些有返回值,有些没有。

print 'foo'; //1
echo  'foo'; //no return value

那么语言结构和内置函数之间的内在区别是什么?

4

4 回答 4

132

(这比我预期的要长;请多多包涵。)

大多数语言都由称为“语法”的东西组成:该语言由几个定义明确的关键字组成,并且您可以用该语言构建的完整表达式范围是由该语法构建的。

例如,假设您有一个简单的四函数算术“语言”,它只将一位整数作为输入并且完全忽略操作顺序(我告诉过您这是一种简单的语言)。该语言可以通过以下语法定义:

// 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 大致相同:语言结构被认为等同于我们的$numberor $operator。它们不能被简化为其他语言结构;相反,它们是构建语言的基本单位。函数和语言构造之间的主要区别在于:解析器直接处理语言构造。它将函数简化为语言结构。

语言构造可能需要也可能不需要括号的原因以及一些具有返回值而另一些不完全取决于 PHP 解析器实现的具体技术细节的原因。我对解析器的工作原理不是那么精通,所以我无法具体解决这些问题,但请想象一下以此开头的语言:

$expression := ($expression) | ...

实际上,这种语言可以自由地采用它找到的任何表达式并去掉周围的括号。PHP(在这里我使用纯粹的猜测)可能会对其语言结构使用类似的东西:print("Hello")可能会减少到print "Hello"解析之前,反之亦然(语言定义可以添加括号也可以去掉它们)。

这就是为什么您不能重新定义诸如echoor之类的语言结构的根源print:它们被有效地硬编码到解析器中,而函数被映射到一组语言结构,并且解析器允许您在编译或运行时将映射更改为替换您自己的一组语言结构或表达式。

归根结底,构造和表达式之间的内部区别是:语言构造由解析器理解和处理。内置函数虽然由语言提供,但在解析之前被映射并简化为一组语言结构。

更多信息:

编辑:阅读其他一些答案,人们提出了很好的观点。其中:

  • 内置语言比函数调用更快。这是真的,即使只是轻微的,因为 PHP 解释器在解析之前不需要将该函数映射到其语言内置等效项。但是,在现代机器上,差异可以忽略不计。
  • 内置语言绕过错误检查。这可能是也可能不是,取决于每个内置函数的 PHP 内部实现。确实,函数通常具有更高级的错误检查和其他内置函数没有的功能。
  • 语言结构不能用作函数回调。这是真的,因为构造不是函数。它们是独立的实体。当您编写内置函数时,您不是在编写带参数的函数 - 内置函数的语法由解析器直接处理,并被识别为内置函数,而不是函数。(如果您考虑具有一流函数的语言,这可能更容易理解:实际上,您可以将函数作为对象传递。您不能使用内置函数来做到这一点。)
于 2009-07-25T01:12:47.260 回答
15

语言结构由语言本身提供(如“if”、“while”等指令);因此他们的名字。

其结果之一是调用它们比预定义或用户定义的函数更快(或者我已经听过/读过几次)

我不知道它是如何完成的,但他们可以做的一件事(因为直接集成到语言中)是“绕过”某种错误处理机制。例如,isset() 可以与不存在的变量一起使用,而不会引起任何通知、警告或错误。

function test($param) {}
if (test($a)) {
    // Notice: Undefined variable: a
}

if (isset($b)) {
    // No notice
}

*请注意,并非所有语言的构造都如此。

函数和语言结构之间的另一个区别是其中一些可以不带括号调用,例如关键字。

例如 :

echo 'test'; // language construct => OK

function my_function($param) {}
my_function 'test'; // function => Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING

在这里,并非所有语言结构都如此。

我想绝对没有办法“禁用”语言结构,因为它是语言本身的一部分。另一方面,许多“内置” PHP 函数并不是真正内置的,因为它们是由扩展提供的,因此它们始终处于活动状态(但不是全部)

另一个区别是语言结构不能用作“函数指针”(我的意思是,例如回调):

$a = array(10, 20);

function test($param) {echo $param . '<br />';}
array_map('test', $a);  // OK (function)

array_map('echo', $a);  // Warning: array_map() expects parameter 1 to be a valid callback, function 'echo' not found or invalid function name

我现在没有任何其他想法......而且我对 PHP 的内部结构了解不多......所以现在就是这样^^

如果你在这里没有得到太多答案,也许你可以向邮件列表内部询问这个问题(参见http://www.php.net/mailing-lists.php),那里有很多 PHP 核心开发人员;他们可能会知道那些东西^^

(而且我真的对其他答案很感兴趣,顺便说一句^^)

作为参考:PHP 中的关键字和语言结构列表

于 2009-07-24T22:06:22.413 回答
4

浏览完代码后,我发现 php 会解析 yacc 文件中的一些语句。所以它们是特殊情况。

(参见 Zend/zend_language_parser.y)

除此之外,我认为没有其他差异。

于 2009-07-24T21:39:00.190 回答
1

您可以覆盖内置函数。关键词是永恒的。

于 2009-07-24T21:43:24.237 回答