93

includeissetrequireprintecho、およびその他のいくつかは関数ではなく言語構造であることを私は知っています。

これらの言語構造には括弧が必要なものもあれば、必要ないものもあります。

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

戻り値を持つものもあれば、持たないものもあります。

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

では、言語構造と組み込み関数の内部的な違いは何でしょうか?

4

4 に答える 4

132

(思ったより長くなりましたが、ご容赦ください。)

ほとんどの言語は「構文」と呼ばれるもので構成されています。言語はいくつかの明確に定義されたキーワードで構成されており、その言語で作成できる式の完全な範囲はその構文から構築されています。

たとえば、入力として 1 桁の整数のみを取り、演算の順序を完全に無視する単純な 4 つの関数を持つ算術「言語」があるとします (これは単純な言語だと言いました)。その言語は、次の構文で定義できます。

// The | means "or" and the := represents definition
$expression := $number | $expression $operator $expression
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
$operator := + | - | * | /

これら 3 つのルールから、任意の数の 1 桁入力算術式を作成できます。$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が 1 つしか残っていないときに結果を吐き出すことができ$numberます。

$expression元の式の最終的に解析されたバージョンには構造が残っていないことに注意してください。それ$expressionは、私たちの言語では常に他のものの組み合わせに還元できるからです.

PHP もほとんど同じです。言語構造は、$numberorと同等のものとして認識されます$operator。それらを他の言語構造に還元することはできません。代わりに、それらは言語が構築される基本単位です。関数と言語構造の主な違いは次のとおりです。パーサーは言語構造を直接扱います。関数を言語構造に単純化します。

言語構造が括弧を必要とする場合と必要としない場合がある理由、および戻り値を持つものとそうでないものがある理由は、PHP パーサー実装の特定の技術的詳細に完全に依存します。私はパーサーがどのように機能するかについてあまり詳しくないので、これらの質問に具体的に答えることができませんが、これで始まる言語をちょっと想像してみてください:

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

事実上、この言語は、見つけた式を自由に取り、周囲の括弧を取り除くことができます。PHP (ここでは純粋な当て推量を採用しています) は、その言語構成体に似たようなものを採用している可能性があります:解析される前にprint("Hello")削減されるprint "Hello"か、またはその逆です (言語定義は括弧を追加したり削除したりできます)。

echoこれが、 orのような言語構造を再定義できない理由の根源printです: 関数は言語構造のセットにマップされ、パーサーはコンパイル時または実行時にそのマッピングを独自の言語構造または式のセットに置き換えます。

結局のところ、構造と式の内部的な違いは次のとおりです。言語構造はパーサーによって理解され、処理されます。組み込み関数は、言語によって提供されますが、解析前に一連の言語構造にマップされ、単純化されます。

より詳しい情報:

  • Backus-Naur 形式、形式言語を定義するために使用される構文 (yacc はこの形式を使用します)

編集:他の回答のいくつかを読んで、人々は良い点を指摘します。その中で:

  • 言語ビルトインは、関数よりも呼び出しが高速です。PHP インタープリターは、解析する前にその関数を言語組み込みの対応する関数にマップする必要がないため、これはほんのわずかではありますが、当てはまります。ただし、最新のマシンでは、違いはほとんどありません。
  • 組み込み言語はエラー チェックをバイパスします。これは、各ビルトインの PHP 内部実装に応じて、真である場合とそうでない場合があります。多くの場合、関数には組み込み関数にはないより高度なエラー チェック機能やその他の機能が備わっていることは確かです。
  • 言語構造は、関数のコールバックとして使用できません。構造体は関数ではないため、これは真です。それらは別個のエンティティです。ビルトインをコーディングするときは、引数を取る関数をコーディングしているのではありません。ビルトインの構文はパーサーによって直接処理され、関数ではなくビルトインとして認識されます。(ファーストクラスの関数を持つ言語を考えると、これは理解しやすいかもしれません。事実上、関数をオブジェクトとして渡すことができます。ビルトインではそれを行うことはできません。)
于 2009-07-25T01:12:47.260 に答える
15

言語構造は、言語自体によって提供されます (「if」、「while」などの命令と同様)。したがって、彼らの名前。

その結果の 1 つは、定義済みまたはユーザー定義の関数よりも呼び出しが高速であることです(または、何度か聞いたり読んだりしたことがあります)。

それがどのように行われるのかはわかりませんが、(言語に直接統合されているため) できることの 1 つは、ある種のエラー処理メカニズムを「バイパス」することです。たとえば、 isset() は、通知、警告、またはエラーを発生させることなく、存在しない変数で使用できます。

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

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

*すべての言語の構造に当てはまるわけではないことに注意してください。

関数と言語構造のもう 1 つの違いは、キーワードのように括弧なしで呼び出せるものがあることです。

例えば ​​:

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

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

ここでも、すべての言語構造に当てはまるわけではありません。

言語自体の一部であるため、言語構成を「無効にする」方法は絶対にないと思います。一方、多くの「組み込み」PHP 関数は、常にアクティブになるように拡張機能によって提供されているため(ただし、すべてではありません) 、実際には組み込みではありません。

もう 1 つの違いは、言語構造を「関数ポインター」として使用できないことです (たとえば、コールバックなど)。

$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の内部についてはあまり知りません...だから、今はそれだけです^^

ここで多くの回答が得られない場合は、多くの PHP コア開発者がいるメーリング リストの内部( http://www.php.net/mailing-lists.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 に答える