Win32でのコンパイル
それでは、Windowsから始めましょう。 ご存知のように 、PHP開発者はVisual C ++ 9またはVisual Studio 2008を使用して、Windowsで頭脳をコンパイルします。 したがって、Visual Studio 2008を使用します。ただし、無料のExpressバージョンも適していますが、おそらく、スタジオの新しいバージョンと古いバージョンが適しています。
必要なもの:
- コンパイル済みのPHP 5.3バイナリは、 ここから取得できます 。
- サイトからダウンロードしたり、 公開SVNからプルしたりできるPHP 5.3ソース
- 実験する意欲と少しの忍耐。
- ソリューションエクスプローラーで右クリックし、[プロパティ]> [C / C ++]> [全般]> [追加インクルードディレクトリ]を選択します。 ここで、展開されたソースコードとPHPヘッダーファイルが配置されているディレクトリを追加します。 具体的には、次のものが必要です。
php-5.3.6 php-5.3.6 \メイン php-5.3.6 \ TSRM php-5.3.6 \ Zend
- プラットフォームの正しい選択とモジュールのコンパイルに必要なプリプロセッサ定義を追加します。 [構成プロパティ]> [C / C ++]> [プリプロセッサ]> [プリプロセッサ定義]を選択し、次を追加します。
PHP_WIN32 ZEND_WIN32 ZTS = 1 ZEND_DEBUG = 0
- 次に、必要なライブラリの場所をリンカーに示します。 [構成プロパティ]> [リンカー]> [全般]> [追加のライブラリディレクトリ]を選択します。 そこで、PHPバイナリから\ divディレクトリを選択します。 「D:\ Program Files \ php-5.3.6-Win32-VC9-x86 \ dev」のようになります。
- ここで、リンカーの特定のリンクを示します。 [構成プロパティ]> [リンカー]> [入力]> [追加の依存関係]に移動し、前の手順で指定したのと同じ\ devディレクトリにあるphp5ts.libを入力します。
- コンパイルの問題を回避するには、[構成プロパティ]> [リンカー]> [コマンドライン]で/ FORCE:MULTIPLEディレクティブを追加します。 詳細については、 MSDN Webサイトをご覧ください。
- 最後に、コンパイル済みのdllを保存する場所を指定できます。 これを行うには、[構成プロパティ]> [リンカー]> [一般]> [出力ファイル名]に移動し、そこにインストールされているPHPの\ extフォルダーへのパスを指定します。 「D:\ Program Files \ php-5.3.6-Win32-VC9-x86 \ ext \ $(ProjectName).dll」のようになります。
#ifndef STDAFX #define STDAFX #define PHP_COMPILER_ID "VC9" // PHP, Visual C++ 9.0 #include "zend_config.w32.h" #include "php.h" #endif
この段階でプロジェクトをコンパイルしようとすると、main \ config.w32.hが見つからないというエラーが表示されます。 main \ configure.batスクリプトを実行するか、ソース(PHPバージョン5.2など)からプルすることで取得できます。 この場合、このファイルのすべてのパスを編集し、「#define HAVE_SOCKLEN_T」ディレクティブのコメントを外すことを忘れないでください。 これで、プロジェクトはエラーなしでコンパイルされます。
hello worldを作成して、cppファイルに次を追加します。
PHP_FUNCTION(test); const zend_function_entry test_functions[] = { PHP_FE(test, NULL) {NULL, NULL, NULL} }; zend_module_entry test_module_entry = { STANDARD_MODULE_HEADER, // #if ZEND_MODULE_API_NO >= 20010901 "test", // test_functions, // NULL, // PHP_MINIT(test), Module Initialization NULL, // PHP_MSHUTDOWN(test), Module Shutdown NULL, // PHP_RINIT(test), Request Initialization NULL, // PHP_RSHUTDOWN(test), Request Shutdown NULL, // PHP_MINFO(test), Module Info ( phpinfo()) "0.1", // STANDARD_MODULE_PROPERTIES }; ZEND_GET_MODULE(test) PHP_FUNCTION(test) { RETURN_STRING("hello habr", 1); // PHP-, , }
このモジュールをPHPに接続して、次のようなものを実行してみてください。
php -r "test();"
答え「hello habr」を取得する必要があります。
* nixでのコンパイル
* nixでは、すべてがいつものようにシンプルになりました。 Debianの例を紹介しますが、他のシステムでもプロセスは変わらないと思います。
以下が必要です。
- マシンにPHPをインストールして、
- PHP-devをインストールしました。 これを行うには、1つのコマンドのみを実行します。
apt-get install php5-dev
config.m4 test.c
1つ目は拡張機能を魔法のようにコンパイルするために必要で、2つ目はそのソースコードです。 config.m4で、次を記述します。
PHP_ARG_ENABLE(test, Enable test support) if test "$PHP_TEST" = "yes"; then AC_DEFINE(HAVE_TEST, 1, [You have test extension]) PHP_NEW_EXTENSION(test, test.c, $ext_shared) fi
test.cの追加
#include "php.h"
そして、この期限の後、cppファイルの内容をWindowsバージョンからコピーします。
次に、コンソールに移動して:
# phpize // # ./configure // makefile # make // # make install // .so PHP
以上です。 これでphp.iniを開き、そこに拡張機能を追加できます:
拡張子= test.so
そして、そのパフォーマンスチームをチェック
php -r "test();"
引数の処理と戻り値
まず、引数を取る方法を見てみましょう。
char* text; int text_length; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &text, &text_lenght) == FAILURE) { return; }
3番目のパラメーターは、予想されるタイプを示します( ここではすべてのオプションを見ることができます)。この場合、char *またはintです。 このリンクには、型を組み合わせて引数の数を指定するためのオプションもあります。 以下のパラメーターはすべて、転送された値が書き込まれる変数です。 文字列を転送すると、文字列自体とその長さが送信されます。
関数に渡された引数の数が一致しない場合、E_WARNINGがスローされますが、エラーメッセージなどの値を返すことができます。
単純型と複合型の両方を返すことができます。 返された配列の形成に慣れてみましょう。 配列が返されることを示すには、初期化する必要があります。
array_init(result);
配列に値を追加するには、どのインデックスと値が配列に追加されるかに依存する関数を使用する必要があります。 例:
add_next_index_long(result, 42); // $result[] = 42; add_assoc_bool(result, "foo", 1); // $result['foo'] = true; add_next_index_null(result); // $result[] = NULL;
機能の完全なリストはここにあります。
誰かが興味を持っているなら、次の記事でオブジェクトを操作する例を検討できます(オブジェクトの拡張機能の典型的な例はmysqliです)。 このトピックに関する非常に良い記事があります。
性能
パフォーマンスをテストするために、文字列内の各文字の出現をカウントする、やや合成的な例を選択しました。 つまり、パラメーターとして文字列を受け取り、特定の文字列内の各文字の使用回数を示す配列を返す関数を取得する必要があります。 この例では、大きな文字列を操作する方法を示します。
私はそのような実装を手に入れましたが、コードをあまり蹴らないでください、私はまだCよりもPHPで書いています:
PHP_FUNCTION(calculate_chars) { char* text; int text_length; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &text, &text_length) == FAILURE) { return; } array_init(return_array); int table[256] = { 0 }; for (int i = 0; i < text_length; i++) { table[((unsigned char*)text)[i]]++; } char str[2]; str[1] = '\0'; for (int i = 0; i < 256; i++) { if (table[i]) { str[0] = (char)i; add_assoc_long(return_array, str, table[i]); } } }
このコードは次の結果を生成します。
user> php -r "print_r( calculate_chars('example') );" Array ( [a] => 1 [e] => 2 [l] => 1 [m] => 1 [p] => 1 [x] => 1 }
ここで、このコードの実行速度とネイティブPHPの同様の実行速度を比較してみましょう。
$map = array(); for ($i = 0; $i < $length; $i++) { $char = $text[$i]; if (isset($map[$char])) { $map[$char]++; } else { $map[$char] = 1; } }
マイクロタイム機能を使用して、両方のソリューションの実行時間を比較します。 100文字の文字列、5000文字の文字列、69,000文字の文字列(Charles Dickensの著書A Message from the Seaを取りました。彼が私を許してくれることを願っています)を選択し、各オプションに対して両方のソリューションを数千回実行します。 結果を下の表に示します。 テストはあまり強力ではない自宅のラップトップとDebianを搭載したVDSで実行されました。はい、結果は構成、オペレーティングシステムのバージョン、PHP、気圧、風向に依存する可能性があることを明確に理解していますが、おおよその数値のみを表示したかったのです。
テストスクリプトの完全なコードは、 ここからダウンロードできます 。 拡張機能自体のソースとバイナリは、 こちら(win)とこちら(nix)からダウンロードできます。
反復回数 | PHPコード/ Win32 | PHPコード/ Debian | PHP拡張/ Win32 | PHP拡張/ Debian | Win32 win | Debianの勝利 | |
1. 100文字の文字列 | 1,000,000 | 84.7566秒 | 72.5617秒 | 8.4750秒 | 4.4175秒 | 10回 | 16.43回 |
2.行5000文字 | 10,000 | 39.1012秒 | 31.7541秒 | 0.5001秒 | 0.134秒 | 78.19回 | 236.98回 |
3. 69,000文字の文字列 | 1000 | 52.3378秒 | 44.0647秒 | 0.4875秒 | 0.0763秒 | 107.36回 | 577.51回 |
結論
解釈されたコードと比較したモジュールのパフォーマンスから判断すると、具体的な結果は、大量のデータと少量の反復で得られることがわかります。 つまり、頻繁に使用されるリソース集約的なアルゴリズムではありませんが、それらをコンパイルされたコードに入れるのは意味がありません。 しかし、大量のデータを処理するアルゴリズムの場合、これは実用的です。 また、私の測定に基づいて、PHPコードの結果は異なるシステムで比較できることがわかります(2つの異なるマシンだったことを思い出します)が、拡張の結果は非常に異なっています。 このことから、私には知られていないコンパイル機能がいくつかあると個人的に結論付けました。 ただし、PHPプロジェクトにWindowsサーバーを使用している人はいないと強く思います。 また、誰かが今すぐCで何かを書き直そうとするのではないかと疑っていますが、この記事はまだ行動のガイドというよりも楽しいものです。 PHP拡張モジュールの記述は非常に簡単で、時には非常に役立つ場合があることを示したかっただけです。
UPD1。 count_charsとの比較
コメントで興味深い質問がされました:count_chars関数のパフォーマンスと比較したらどうでしょうか?
繰り返し回数を100回増やし、同じテストを実行しましたが、既にこの関数を使用しています。 Debianでの結果はほぼ同等であり、Windowsでは興味深い状況があります。データが多いほど、パフォーマンスが向上するのは私のモジュールです。 テストのアイデアは自転車を書くことではなく、大量のデータを処理するアルゴリズムを採用することでした。
反復回数 | count_chars / win32 | count_chars / Debian | 拡張機能/ win32 | 拡張機能/ Debian | Win32 win | Debianの勝利 | |
1. 100文字の文字列 | 10,000,000 | 67.5245秒 | 47.8104秒 | 81.8185秒 | 43.8091秒 | 0.83回 | 1.09回 |
2.行5000文字 | 1,000,000 | 22.4693秒 | 12.8959秒 | 47.2514秒 | 12.9577秒 | 0.48回 | 0.99回 |
3. 69,000文字の文字列 | 100,000 | 15.0681秒 | 7.661秒 | 46.9598秒 | 7.7387秒 | 0.32回 | 0.99回 |
素材
- PHPのコア:Zend Engineハッカーのガイド、 php.net
- phpize、php.netを使用して共有PECL拡張機能をコンパイルする
- Microsoft Visual C ++ 2008、 talkphp.comを使用してWindows用のPHP拡張機能を作成する
- 拡張機能作成パートI:PHPとZendの紹介、 devzone.zend.com
- 拡張機能作成パートII:パラメーター、配列、ZVAL、 devzone.zend.com
- PHP拡張モジュール 、 devzone.zend.comでのC ++クラスのラップ