前回の検討で、サーバー側での PHP ファイルの実行処理には、大きく次の 2 つの処理があることが分かりました。
2 番目のステップでは、字句解析、構文解析、中間コードのコンパイル、中間コードの実行などを総称して Zend 仮想マシンと呼びます。 Java や C# などのコンパイル済み言語と比較して、PHP は手動のコンパイル プロセスを必要とせず、コンパイルなしで実行できます。 Java には、複数のプラットフォームで統一された言語を実装する独自の Java 仮想マシンがあり、C# には、単一のプラットフォームで複数の言語を実装する独自の .NET 仮想マシンがあります。PHP も同様に、独自の Zend 仮想マシンを持っています。これらは本質的に同じであり、両方とも抽象コンピュータです。 これらの仮想マシンは、低レベル言語から別の言語を抽象化し、独自の命令セットと独自のメモリ管理システムを備えています。 最終的には、より高い抽象レベルの言語実装をより低い抽象レベルの言語実装に変換し、メモリ管理、ガベージ コレクション、その他のメカニズムなどの他の補助機能を実装して、特定の実装に対するプログラマの作業を軽減し、より多くの時間を費やすことができます。ビジネス ロジックに投資された労力。 抽象的なレベルで見ると、Zend 仮想マシンは Java や他の言語よりも高度です。ここでいう高度とは、簡単に言うと、Zend 仮想マシンが実際のマシンの実装から遠く離れていることを意味します。 。 近年、言語の発展は抽象的なものばかりが続き、根本的な変化はなく、常に機械から遠ざかっています。
ここでは、仮想マシンの過去と現在から始めて、構文の実装例とソース コード暗号化のプロセスの説明を交えながら、Zend 仮想マシンの実装原理と主要なデータ構造について説明します。そして復号化。
Wiki における仮想マシンの定義は次のとおりです: 仮想マシン (Virtual Machine) は、コンピュータ サイエンスのアーキテクチャにおいて、コンピュータ プラットフォームとエンド ユーザー環境の間で作成できる特別なソフトウェアを指します。エンドユーザーは、ソフトウェアによって作成された環境に基づいてソフトウェアを操作します。 コンピューター サイエンスでは、仮想マシンとは、実際のマシンのようにプログラムを実行できるコンピューターのソフトウェア実装を指します。
仮想マシンは、独自の命令セットと独自のメモリ管理システムを備えた抽象的なコンピューターです。 このような仮想マシンに実装された言語は、より低い抽象レベルの言語よりも明確で、学習が容易です。
PHP ファイルはどのように解析されますか? 生成された中間コードは実際の PHP コードとどのように対応していますか? 実行中にどのような中間データが保存されますか?仮想マシン全体を最適化できますか?最適化するにはどうすればよいですか?
Zend 仮想マシンの実装を概念層から抽象化すると、Zend 仮想マシンのアーキテクチャを解釈層、実行エンジン、中間データ層に分割できます。
Zend 仮想マシンのアーキテクチャ図
PHP コードの一部が Zend 仮想マシンに入ると、コンパイルと実行という 2 つのステップが実行されます。 これはインタープリター言語にとって創造的な動きですが、現在の実装は不完全です。 PHP コードが Zend 仮想マシンに入ると、これら 2 つのステップで実行されますが、これらの 2 つのステップは通常の実行プロセスでは連続しています。つまり、Java のようなものに変換されていないのと同じです。言語: コンパイルされた結果を保存するために中間ファイルが生成されます。 このような操作を毎回実行すると、PHP スクリプトのパフォーマンスに大きな損失が生じます。 APC、eAccelerator などに似たキャッシュ ソリューションもありますが、しかし、その本質は変わっておらず、2 つのステップを分離して別々に開発することはできません。
解釈層は、Zend 仮想マシンがコンパイル プロセスを実行する場所です。これには、字句解析、構文解析、中間コードを生成するコンパイルの 3 つの部分が含まれます。 字句解析とは、実行したいPHPソースファイルからスペースやコメントを取り除き、トークンに分割し、プログラムの階層構造を処理することです。
文法分析は、定義された文法規則に従って、受け入れられたトークン シーケンスに基づいていくつかのアクションを実行することです。Zend 仮想マシンで現在使用されている Bison は、Backus Normal Form (BNF) を使用して文法を記述します。 中間コードのコンパイルと生成は、構文解析の結果に基づいて行われ、PHP5.3.1 では、Zend 仮想マシンは 135 の命令をサポートします (Zend/zend_vm_opcodes.h ファイルを参照)。これは単純な出力ステートメントです。プログラム内の複雑な再帰呼び出しであるかどうかに関係なく、Zend 仮想マシンは最終的に、作成したすべての PHP コードをこれらの 135 命令のシーケンスに変換し、実行エンジンで順番に実行します。
Zend 仮想マシンが PHP コードを実行する場合、中間コード、PHP 独自の関数リスト、ユーザー定義関数リスト、PHP 独自のクラス、ユーザー定義のクラス、定数、プログラムによって作成されたオブジェクト、関数またはメソッドに渡されるパラメーター、戻り値、ローカル変数、および一部の操作の中間結果など。 データが保存されるこれらすべての場所を中間データ層と呼びます。
PHP が MOD 拡張機能として Apache2 サーバーにアタッチされている場合、PHP に付属する関数リストなど、中間データ層の一部のデータが複数のスレッドで共有される可能性があります。 単一のプロセスのみを考慮すると、プロセスが作成されると、PHP に付属するさまざまな関数リスト、クラス リスト、定数リストなどがロードされます。 解釈層が PHP コードをコンパイルすると、さまざまなユーザー定義関数、クラス、または定数が前のリストに追加されますが、これらの関数の構造における特定のフィールドの割り当ては異なります。
実行エンジンが生成された中間コードを実行すると、新しい実行中間データ構造 (zend_execute_data) が Zend 仮想マシンのスタックに追加されます。これには、現在の実行のアクティブなシンボル リストのスナップショットが含まれますプロセス、いくつかのローカル変数など。
Zend 仮想マシンの実行エンジンは、中間コード シーケンス (EX(opline)) に基づいて、対応するメソッドを段階的に呼び出すだけの非常に単純な実装です。 実行エンジンには、次の命令を格納するための PC レジスタのような変数はありません。Zend 仮想マシンが特定の命令を実行するとき、そのすべてのタスクが実行されると、この命令は単独で次の命令を呼び出します。シーケンス ポインタは 1 つ前に移動して次の命令を実行し、最後に return ステートメントを実行します。 これは本質的にはネストされた関数呼び出しです。
元の質問に戻りますが、PHP が字句解析、構文解析、中間コード生成の 3 つのステップを通過した後、PHP ファイルは PHP の中間コード オペコードに解析されます。 生成された中間コードと実際の PHP コードの間には、完全な 1 対 1 の対応関係はありません。ユーザーが指定した PHP コード、PHP の構文規則、および一部の内部規則に基づいて中間コードを生成するだけであり、これらの中間コードは、データと関連付けを転送するためにいくつかのグローバル変数にも依存する必要があります。生成された中間コードの実行処理は、中間コードの滑らかさと実行処理におけるグローバル変数に依存し、ステップバイステップで実行されます。もちろん、関数ジャンプに遭遇したときにオフセットも発生しますが、最終的にはオフセット ポイントに戻ります。
この記事のトピックのリストは次のとおりです: