ホームページ  >  記事  >  バックエンド開発  >  PHP7 の新機能の抽象構文ツリー (AST) についてのいくつかの紹介

PHP7 の新機能の抽象構文ツリー (AST) についてのいくつかの紹介

不言
不言オリジナル
2018-07-21 12:59:122190ブラウズ

この記事では、PHP7 の新機能の抽象構文ツリー (AST) について説明します。内容は非常に優れています。困っている友人は参照してください。すべての人に役立つことを願っています。

この記事では、PHP7 の新機能である抽象構文ツリー (AST) によってもたらされた変更を分析します。次のように、参照用に全員と共有してください。

ここでの内容のほとんどは、AST の RFC 文書 https://wiki.php.net/rfc/abstractsyntaxtree に基づいています。理解を容易にするためにソースドキュメントのセクションが導入されています。

この記事では、抽象構文ツリーが何であるかについては説明しません。これについては各自で理解する必要があります。この記事では、AST が PHP にもたらすいくつかの変更についてのみ説明します。

新しい実行プロセス

PHP7 のコアにおける重要な変更は、AST の追加です。 PHP5 では、php スクリプトからオペコードまでの実行プロセスは次のとおりです:

  1. 字句解析: 字句スキャン分析、ソース ファイルをトークン ストリームに変換します;

  2. 解析: 構文解析、op 配列がこの段階で生成されます。

PHP7 では、op 配列は構文分析フェーズ中に直接生成されなくなりましたが、AST が最初に生成されるため、プロセスにはもう 1 つのステップがあります。

    Lexing : 字句スキャン分析、ソース ファイルをトークン ストリームに変換します;
  1. Parsing : 構文分析、トークン ストリームから抽象構文ツリーを生成します;
  2. コンパイル: 抽象構文ツリーから op 配列を生成します。
  3. 実行時間とメモリ消費量

上記の手順から、これは前のプロセスよりも 1 つの手順が多いため、常識的には、これによりプログラムの実行時間が増加します。時間とメモリの使用量。しかし実際には、メモリ使用量は確かに増加していますが、実行時間は減少しています。

次の結果は、小規模 (約 100 行のコード)、中規模 (約 700 行)、および大規模 (約 2800 行) の 3 つのスクリプトをテストして得られたものです。テスト スクリプト: https://gist.github .com/nikic/289b0c7538b46c2220bc.

各ファイルを 100 回コンパイルした場合の実行時間 (記事のテスト結果は、PHP7 がまだ PHP-NG と呼ばれていた 14 年間のものであることに注意してください):

php-astdiff SMALL0.180s0.160s-12.5%MEDIUM1.492s1.268s-17.7%大6.703s5.736s- 16.9% 単一コンパイルでのメモリ ピーク:
#php-ng

php-astdiffSMALL378kB414kB 9.5 %#MEDIUM507kB643kB 26.8%LARGE1084kB1857kB 71.3%##単一コンパイルのテスト結果は、実際の使用を表すものではない可能性があります。以下のとおりです。以下は、PhpParser を使用した完全なプロジェクト テストの結果です:
php- ng

##php-ngdiffTIME25.5ms22.8ms-11.8%メモリ2360kB2482kB 5.1%

テストによると、AST を使用した後、プログラムの全体的な実行時間は約 10% ~ 15% 改善されましたが、メモリ消費量も増加しました。この増加は、大きなファイルの 1 回のコンパイルでは明らかですが、実行中はそうではありません。プロジェクトの実行プロセス全体が非常に深刻な問題です。

また、上記の結果はすべて Opcache を使用していないことにも注意してください。運用環境で Opcache がオンになっている場合、メモリ消費量の増加は大きな問題ではありません。

セマンティックな変更

これが単なる時間の最適化である場合、AST を使用する十分な理由にはならないようです。実際、AST の実装は時間の最適化を考慮したものではなく、構文の問題を解決するために行われています。セマンティクスにおけるいくつかの変更を見てみましょう。

yield には括弧は必要ありません

PHP5 実装では、式コンテキスト (代入式の右側など) で yield が使用される場合、 yield 宣言の両側で括弧を使用する必要があります:

<?php
$result = yield fn(); // 不合法的
$result = (yield fn()); // 合法的

この動作は、PHP5 の実装の制限によるものです。PHP7 では、括弧は必要ありません。したがって、次の記述方法も合法です。

<?php
$result = yield;
$result = yield $v;
$result = yield $k => $v;

もちろん、yield のアプリケーション シナリオに従う必要があります。

括弧は動作に影響しません

PHP5 では、($foo)['bar'] = 'baz' および $foo['bar'] = 'baz' 2 つのステートメントは異なる意味を持ちます。実は、前者の書き方は違法であり、次のようなエラーが発生します。

<?php
($foo)[&#39;bar&#39;] = &#39;baz&#39;;
# PHP Parse error: Syntax error, unexpected &#39;[&#39; on line 1

しかし、PHP7 では、2 つの書き方は同じ意味になります。

同様に、関数のパラメータが括弧で囲まれている場合、型チェックに問題があります。この問題は PHP7 でも解決されています:

<?php
function func() {
 return [];
}
function byRef(array &$a) {
}
byRef((func()));

上記のコードは、次の場合には警告しません。 ##byRef(func()) を使用しない限り、PHP5 では ##byRef(func()) が使用されますが、PHP7 では、func() の両側に括弧があるかどうかに関係なく、次のエラーが発生します。

PHP の厳格な標準: 変数のみが参照によって渡される必要があります...

list() の変更点

list キーワードの動作は大幅に変更されました。リストが変数に値を割り当てる順序 (等号の左右の順序) は、以前は右から左でしたが、現在は左から右です:

<?php
list($array[], $array[], $array[]) = [1, 2, 3];
var_dump($array);
// PHP5: $array = [3, 2, 1]
// PHP7: $array = [1, 2, 3]
# 注意这里的左右的顺序指的是等号左右同时的顺序,
# list($a, $b) = [1, 2] 这种使用中 $a == 1, $b == 2 是没有疑问的。

上記の変更の理由は、PHP5 の代入プロセスでは、最初に 3 が配列に入力され、最後に 1 が入力されるためですが、順序が変更されたためです。

同じ変更は次のとおりです:

<?php
$a = [1, 2];
list($a, $b) = $a;
// PHP5: $a = 1, $b = 2
// PHP7: $a = 1, $b = null + "Undefined index 1"

これは、前の代入プロセスで $b が最初に 2 を取得し、その後 $a の値が 1 になったためです。しかし、今回は $a が最初に変更されます。は 1 になり、配列ではなくなるため、$b は null になります。

list はオフセットごとに 1 回だけアクセスされるようになりました:

<?php
list(list($a, $b)) = $array;
// PHP5:
$b = $array[0][1];
$a = $array[0][0];
// PHP7:
// 会产生一个中间变量,得到 $array[0] 的值
$_tmp = $array[0];
$a = $_tmp[0];
$b = $_tmp[1];

以前は特定の状況下でのみ空のリスト メンバーがすべて禁止されました:

<?php
list() = $a;   // 不合法
list($b, list()) = $a; // 不合法
foreach ($a as list()) // 不合法 (PHP5 中也不合法)

参照割り当ての順序

PHP5 では参照割り当ての順序は右から左でしたが、現在は左から右です:

<?php
$obj = new stdClass;
$obj->a = &$obj->b;
$obj->b = 1;
var_dump($obj);
// PHP5:
object(stdClass)#1 (2) {
 ["b"] => &int(1)
 ["a"] => &int(1)
}
// PHP7:
object(stdClass)#1 (2) {
 ["a"] => &int(1)
 ["b"] => &int(1)
}

__clone メソッドを直接呼び出すことができます

## を直接使用できるようになりました。 #$obj->__clone()

を使用して、__clone メソッドを呼び出します。 __clone は、以前は直接呼び出すことが禁止されていた唯一のマジック メソッドです。以前は、次のようなエラーが発生していました: 致命的エラー: オブジェクトに対して __clone() メソッドを呼び出すことができません - ' を使用してくださいclone $ obj' の代わりに...

変数構文の一貫性

AST は、別の RFC: https://wiki.php.net/rfc/ で提起されたいくつかの構文の一貫性の問題も解決します。 uniform_variable_syntax.

新しい実装では、以前の一部の文法表現の意味が現在のものと多少異なります。詳細については、次の表を参照してください:

php-ast
#式PHP5PHP7${ $foo['bar']['baz']}$foo->{$bar['baz']}$foo->{$bar['baz']}( )##Foo::$bar['baz']()Foo:: {$bar['baz']}()(Foo::$bar)['baz']()関連する推奨事項:
##$$foo['bar']['baz']
($$foo)['bar']['baz'] $foo-> ;$bar['baz']
($foo->$bar)[' baz'] $foo->$bar['baz']()
($foo->$bar)['baz']()
全体的には、以前の順序は右から左でしたが、現在は左から右です。また、括弧は動作に影響を与えないという原則に従います。このような複雑な変数の書き方は、実際の開発では注意が必要です。

php エラー エコー情報をオフにする 5 つの方法

php の FastCGI プロトコルソースコード分析

以上がPHP7 の新機能の抽象構文ツリー (AST) についてのいくつかの紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。