http://www.thinkphp.cn/topic/10421.html
phpのコンパイルと実行は分離されています。つまり、コンパイルが最初に完了してから実行されます。多くの人は、「確かに、C++ にも同じことが当てはまります」と言うでしょう。ただし、この PHP の分離により、多くの利便性が得られますが、もちろん、多くの欠点もあります。
まずプロセス全体について話しましょう: ①phpはコンパイル関数zend_compile_file()を呼び出してコンパイルします。 この関数の具体的な実装には、実際には字句解析 (Lex 実装) と構文解析 (Yacc 実装) という 2 つの主要なプロセスが含まれます。この関数を実行すると、php スクリプトのコンパイルが完了します。 この関数の入力は php スクリプト ファイル、出力は op_array です。簡単に言うと、Sun City のコンパイル プロセスは、スクリプトを php 仮想マシンで処理できる命令に解析することです。
op_array は、これらの命令で構成される単なる配列です (これは、一部のコンパイル言語によって生成されるアセンブリ コードに非常によく似ていますが、これも 1 つずつコマンドです)。 ②: 次に、php仮想マシンはzend_execute()関数を呼び出して実行します。この関数の入力は、上記のコンパイル段階で生成された op_array であり、各コマンドを解析して処理します。 op コマンドは合計で約 150 個あるため、この 150 個のコマンドを処理する必要があります。ここで非常に興味深い疑問が生じます。これらの 150 個のコマンドはどのように処理されるのでしょうか?まず、各コマンドには対応するものがあります。
処理を行うプロセッサー。したがって、仮想マシンは、op_array 内の各コマンドのタイプに基づいて、対応するプロセッサに分散されて処理されます。 ここで 2 つの小さな質問があります: 1: ここのプロセッサは何ですか? 2: どのように配布されますか?これら 2 つの質問に答えるには、分散メカニズムから説明する必要があります。PHP 仮想マシンには、CALL、SWITCH、および GOTO という 3 つのメカニズムがあり、デフォルトで CALL メソッドが使用されます。関数として定義され、
その後、システムは仮想マシンによって呼び出されます。この方法は従来の方法であり、一般に最も安定した方法と考えられています。SWITCH メソッドと GOTO メソッドは、switch と goto を使用して、実行のためにオペコードを対応する処理ロジック (セグメント) に配布します。 . それでは、上記の 2 つの質問に答えてみましょう: 1: プロセッサは、op コマンドのロジックを実際に処理します。コマンドの配布方法に応じて、関数または論理セグメントの形式で存在できます。 2:コール、スイッチ、gotoの3つの配信方法があります。どちらがより効率的ですか?実際、上記の説明からすでに予備的な理解を得ることができます。 switch と goto の両方には、zend_execute() 関数内に対応する論理セグメントがあり、直接実行できます。この呼び出しは、zend_execute() 関数内の関数呼び出しを実行することです。明らか
注: 関数呼び出しの効率は、一度呼び出した場合はスタックにプッシュする必要があります。したがって、効率の観点から言えば、コールが最も低くなっています。 switch と goto の場合: たとえば、3 番目のコマンドを実行する場合: switch は最初に最初の 2 つであるかどうかを判断する必要がありますが、goto は判断する必要がまったくなく、3 番目のコマンドの論理コード セグメントに直接ジャンプします。実行に関しては、Switch よりも優れており、上から下への順序判断の損失が軽減されます。そのため、Goto の効率は Switch よりも高くなります。したがって、これら 3 つの分散メソッドは一般に本題から外れています。PHP のデフォルトは call なので、PHP のパフォーマンスをさらに絞り込みたい場合は、そのコマンド分散メソッドを goto に変更できます。ただし、goto メソッドを使用すると実行速度は向上しますが、コンパイル速度は実際には最も遅くなります。 PHP のコンパイルと実行の分離の弱点について話しましょう。実際、zend ではありますが、それは弱点とみなされません。
エンジン (php の仮想マシン) はコンパイルと実行を厳密に分離しますが、Suncity ユーザーにとっては、それらが分離されていないように見えます。PHP スクリプト リクエストを実行するたびに、コンパイル -> 実行という 2 つの段階を実行する必要があるためです。欠けているステージはありません。そこで、これをC++のようなコンパイル言語と比較してみましょう: 同じリクエストを100回実行します ①C++の場合、初期段階で一度コンパイルするだけなので、コンパイル後に再度コンパイルされることはありません。 , したがって、損失は次のとおりです: 1回のコンパイル + 100回の実行 ② phpの場合、毎回コンパイル+実行する必要があるため、損失は次のようになります: 100回のコンパイル + 100回の実行 明らかに: 定量的な点から見解としては、インタープリタ言語はコンパイル言語よりもはるかに多くの電力を消費します。率直に言うと、PHP のコンパイルと実行の分離は、本当の意味での分離ではありません。 C++ の種類が実際の分離です。 PHP はこの問題を長い間認識していたため、この問題を解決する方法を考え出しました。この解決策が eAccelerator です。主な考え方は次のとおりです。スクリプトが初めて実行されると、コンパイルされたスクリプトは指定されたキャッシュ有効期間内に保存されますが、スクリプトが 2 回目に実行されると、保存されなくなります。コンパイル作業を繰り返し実行しますが、以前に保存したコンパイル済みファイルを直接呼び出して実行すると、プログラムのパフォーマンスが大幅に向上します。 この方法は PHP の効率をある程度向上させますが、究極の方法ではありません。最後に、PHP のコンパイルと実行を分離することの利点について説明します。利点は実際には、ユーザーではなくプログラマのためであることです。これら 2 つの段階が分離されているため、http://tyangcdh.com がやりたいことのいくつかをここで実行できます。 たとえば、ファイルの暗号化と復号化を行う場合、一部の PHP スクリプトのソース コード ファイルを暗号化して、ユーザーがソース コードを見られないようにする必要があります。同時に、この暗号化されたソース コード ファイルは、PHP 仮想マシンによって解析および処理できます。もちろん、これを実現するには、まず暗号化と復号化のアルゴリズムを検討し、これが可逆的なプロセスであることを確認する必要があります。 PHP ソース コード ファイルを暗号化したので、この暗号化されたファイルのサフィックス 6 を定義する必要があります (そうであると仮定します)。
そこで質問は、PHP 仮想マシンがこのサフィックスを持つファイルを処理できるようにするにはどうすればよいでしょうか?これには、前述したコンパイルと実行を分離する必要があります。思い出してください: コンパイル段階への入力は php ソース ファイルであり、出力は op_array です。さて、この段階では大騒ぎしましょう。主なアイデアは次のとおりです。まず、コンパイル関数 zend_compile_file() で、入力ファイルのサフィックスを確認します。それが通常の .php の場合は、通常のロジックに従います。*.buaa の場合は、最初に復号化してから次の手順を実行します。通常のロジック。はぁ~簡単ですね。もちろん、このプロセスは前述したほど単純ではなく、zend_compile_file() 関数を直接変更することはできません。最終的には、このプロセスを処理するためにモジュールを自分で拡張して実装する必要があります。
上記では、内容の側面も含めて PHP のいくつかの原則を紹介しましたが、PHP チュートリアルに興味のある友人に役立つことを願っています。