JPHP-Java VM + JIT用の新しいphpエンジン

オープンソースプロジェクトJPHPを紹介します。 これは、JITをサポートするJavaVMの代替PHP実装です。 私は2013年10月にプロジェクトを単独で開始し、4か月後にJVMバイトコードにphpコンパイラを実装しました。 この言語はPHP 5.3のレベルでサポートされ、PHP 5.4および5.5の機能は部分的にサポートされています。 そのイデオロギーでは、プロジェクトはJRubyとJythonに似ています。



私はプロジェクトについて話す小さなプレゼンテーションを用意しましたが、あまり時間はかかりません:







このプロジェクトについてできる限り話したいという願望がありますが、すべてを1つの記事に収めるのは怖いです。 乱雑ではないことを願っています。








プロジェクト目標



JPHPはZend PHPやFacebook HHVMの代替ではありません。CURL、PRCE、PDOなど、すべてのランタイムzend phpライブラリを実装する計画がなかったためです。 プロジェクトを開始した主な理由は次のとおりです。







技術的な詳細



言語全体はバイトコードを生成するためにASMライブラリを使用してJavaでゼロから記述され、Groovyなどのすべての一般的なjvm言語で使用されます。 Gradleがビルドシステムとして選択されました。



驚いたことに、Javaテクノロジースタックは、jvm言語を記述するための非常に便利な条件を提供します。 JITでVMを記述する必要はありません。ガベージコレクターとクラスシステムは既に実装されています。クロスプラットフォームについて頭痛の種はありません。また、jvmバイトコード自体は非常に理解しやすいです。 しかし、多くの落とし穴がありました。何よりも、PHP言語自体の魔法によるものです。



JITにより、テストに応じて生産性を1〜10倍、実際のコードで平均1.5〜3倍向上させることができました。 また、コードの高速化に役立つオプティマイザーも実装しました。



PHPの互換性?



言語とライブラリを区別する価値があるため、言語とライブラリのレベルでの互換性は2つの異なるものです。 開発の初期段階で、私はすべてのPHPライブラリを1人に対して適切な互換性で記述することは不可能であることに気付きました。 言語のみに集中することにしましたが、splの自動読み込み、Reflection、ob_ *関数、 <? ... ?>



<? ... ?>



など。



JPHPは、OOP、関数、演算子などのテストを含む、元のZend PHPからの約300以上のユニットテストに合格します。 テストもあります。 これは、言語が適切に機能していることを確認するのに役立ちます。 次に、サポートされている機能をリストします。







PHP 5.4からの特性の実装途中。



JITとパフォーマンス



どのコードがパフォーマンスに影響すると思いますか? Facebook HHVMに精通しているなら、どれを知っていると思います。 PHPのパフォーマンスに関する主な問題は、変数のグローバルスペース、変数の魔法、実行時に名前で変数にアクセスできる場合の魔法です。 このため、JPHPは同じコードをさまざまな方法でコンパイルできます。 変数に魔法がない場合、コンパイラは変数をインデックスに変換し、実行時にインデックスによってすぐにアクセスします。 例を挙げましょう。



 $var = 'foobar'; $x = 'var'; ${$x} = 'chanched'; //  
      
      





 $global_var = 100500; include 'file.php'; //  ,  include   global scope  
      
      





 function foobar() { $x = 100500; $var = get_defined_vars(); //    }
      
      







したがって、実行時に名前で変数を参照することになっている場合、JPHPは変数名のテーブルを保存し、そうでない場合には、インデックスによって変数を保存せず、すぐに参照します。



変数の魔法は、JPHPでコードを約2倍遅くすることです。 Zend PHPでは、コードはすべての条件下で同じように機能します。



オプティマイザー



JPHPオプティマイザーは非常に多くのことを実行できます。ここにその機能の短いリストがあります。



1.定数式

 $x = (20 + 30) . 'foobar'; //     1 
      
      







2.静的定数

JPHPがコンパイル時に知っている定数があり、 define



を介して宣言された動的定数がありdefine



。 静的は、システム定数__FILE__, __DIR__, __CLASS__



、java拡張定数、 const



介して同じファイル内で宣言される定数です。 それらはすべて、コンパイル時に置き換えることができます。

 include __DIR__ . '/core.php'; //     
      
      







3.不変の関数とメソッド

これらは結果が変わらない関数またはメソッドであるか、コンパイル中に一度計算できるものであり、グローバル環境に影響を与えないため安全です。



 for ($i = 0; $i < 100500; $i++){ $x = cos(1) + 3; //  1    ,   100500 }
      
      





この例では、関数cos()は体系的で不変であり、関数に渡されるパラメーターは定数であるため、cos(1)の結果は決して変化しません。



パラメーターを持たず、定数式を返す、プログラマーによって宣言された不変のインクルード関数/メソッド。 JPHPでそのような関数を呼び出すことは、定数の呼び出しに速度が匹敵します。例えば:



 function getVersion(){ return '1.0'; } $x = getVersion(); //   define('VERSION', '1.0'); $x = VERSION; //    =    
      
      







4.不可能な条件

ifまたはelseifで定数式がすべてfalseの場合、コンパイラは不要な条件をまったく拒否します。 これまでのところ、elseおよびelseifがサポートされている場合のみ。 たとえば、これは非常に便利です。



 if (TRACE_ENABLED){ //  TRACE_ENABLED = false,       log("Log text..."); }
      
      







クラス、関数、バイトコードをキャッシュしていますか?



JPHP作業モデルを使用すると、コンパイルされたコードをメモリに保存できます。 クラスと関数。 コンパイルおよびロードされたクラスは繰り返し使用されます。 将来的には、PHP自体でPhalconに劣らないパフォーマンスフレームワークであるhttpサーバーを作成できるようになります。 データはリクエスト間で簡単に保存でき、httpサーバーはphp自体に書き込むことができます。これについては以下で説明します。



JPHPには、スクリプトを実行するための隔離された環境を作成できる特別なEnvironmentクラスがあります。これは、runkit拡張のサンドボックスのようなものです。 そのような各環境には、独自のクラス、関数、およびグローバル変数のセットがあります。







以下の例でこのクラスを使用して、マルチスレッドhttpサーバーを編成します。



どうやって試すの? テストプロジェクトを構築しますか?



これを行うには、Java(1.6+)およびGradleビルドシステム(1.4+)をインストールする必要があります。 gitリポジトリからソースをダウンロードします。 JetBrains IDEAでは、build.gradleからプロジェクトをインポートできます。 この段階では、 jphp-example-project



フォルダーにテストプロジェクトがあります。 このプロジェクトは実行可能なjarファイルにコンパイルされ、その中にphpソースがあります。 jarが起動すると、 bootstrap.php



ファイルが実行されます。 次のコマンドを使用してjarをビルドできます。



 gradle jar
      
      





またはすぐに実行します:



 gradle exampleStart
      
      







プロジェクトは、jarファイルのbuild/libs/



フォルダーにアセンブルされます。



GUI? プログラム?



また、Swing(GUI用のJavaライブラリー)のラッパー拡張機能も作成しました。 クロスプラットフォームのGUIプログラムを作成できます。 Swingに精通している人のために、私は安心したいです-私はAPIとレイアウトシステムをかなり単純化しました。 GUIの小さなウィンドウ:



  use php\lang\System; use php\swing\SwingUtilities; use php\swing\UIForm; use php\swing\UIDialog; use php\swing\UIButton; SwingUtilities::invokeLater(function(){ $form = new UIForm(); $form->size = [500, 500]; $form->moveToCenter(); $form->visible = true; $p = new UIButton(); $p->size = [300, 40]; $p->align = 'top'; $p->h = 30; $p->text = ''; $p->on('click', function(){ UIDialog::message('', ''); }); $form->add($p); $form->on('windowClosing', function(){ System::halt(0); }); });
      
      







マルチスレッドHTTPサーバー?



JPHPでは、マルチスレッドhttpサーバーを作成できます。 これを行うために、私はSocket



およびServerSokect



、およびThread



スレッドクラスをインポートしました。



  use php\concurrent\ExecutorService; use php\io\IOException; use php\lang\Environment; use php\net\ServerSocket; $server = new ServerSocket(); $server->bind('localhost', 8080); $service = ExecutorService::newFixedThreadPool(5); // create a thread pool echo "Start HTTP Server on http://localhost:8080/ ...\n"; while (true) { $socket = $server->accept(); echo "Connect client ... \n"; $service->execute(function() use ($socket) { // processing a http request in a thread ob_implicit_flush(true); $out = $socket->getOutput(); try { $out->write("HTTP/1.1 200 OK\r\n"); $out->write("Content-Type: text/html\r\n"); $out->write("Connection: close\r\n\r\n"); $out->write("Hello world!"); $out->flush(); } catch (IOException $e) { echo "Error: " . $e->getMessage(), "\n"; } finally { // JPHP supports `finally` as in PHP 5.5 $socket->shutdownOutput(); } }, new Environment()); }
      
      







このようなサーバーはコンテンツを非常に迅速に提供し、abユーティリティでテストしましたが、結果は印象的です。 私のマシン(Java 7、i3、Windows 7)では、このようなサーバーは1秒あたり4000〜5000のリクエストを処理できます( ab -n50000 -c100 localhost



ab -n50000 -c100 localhost



)に該当します。



次は?



私は自分でJPHPを開発し、リリースして、すべての言語機能をPHP 5.5に実装する予定です。 おそらく、Androidとの互換性の実装を試みます(JRuby用のRobotoの例に従って)。 私は名前空間とOOPに基づいて通常の拡張機能を実装しますが、部分的には既に何かを実装しています-ストリーム、ソケット、GUI、JSON。



プレゼンテーションの残りの部分を参照してください。 ご清聴ありがとうございました。



All Articles