ホームページ  >  記事  >  バックエンド開発  >  PHP変換旧暦C拡張開発

PHP変換旧暦C拡張開発

WBOY
WBOYオリジナル
2016-06-23 13:15:42821ブラウズ

この記事は主に PHP 拡張機能の開発に慣れることを目的としています。 太陰暦拡張機能を開発しても役に立たないようです。 PHP の成功の理由の 1 つは、強力な拡張機能があり、開発者が独自の PHP 拡張機能を柔軟に開発できることです。私は LNMP スタック エキスパートになることに全力で取り組んでいます (また誤って B のふりをしてしまいました)。もちろん、学ぶべきことや専門化すべきことがたくさんあります。 !

PHP 拡張機能の開発

拡張関数定義ファイル

まず関数定義ファイルを定義します。これは thrift の IDL ファイルよりもはるかに簡単です。関数定義ファイルは、拡張機能が提供する関数プロトタイプを定義します。一般的な形式は、1 行に 1 つの関数です。関数定義では、戻り値と、bool、float、int、array などの受信パラメータの型を指定する必要があります。旧暦計算用の関数定義ファイルは以下の通りです:

string datetolunar(int year, int month, int day);

もちろん、同じ関数定義ファイル内に複数の関数を定義することもできますし、クラスを作成し、対応する関数クラス拡張スケルトンを生成できるようにします。例:

class Lunar {

string datetolunar(int year, int month, int day);

}

PHP 拡張スケルトンを生成する

PHP ソースの ext/ ディレクトリに ext_skel スクリプトがありますコードディレクトリ。先ほど定義した旧暦拡張機能定義ファイルlunar.skelを基に拡張スケルトンを生成します。

~# ./ext_skel –extname=datetolunar –proto=lunar.skel

extname は生成された拡張子名を表します。実行後、datetolunar ディレクトリが ext/ ディレクトリに生成されます。

tiger➜php-5.6.17/ext/datetolunar» ls [14:44:36]クレジット実験 config.m4 config.w32 datetolunar.c datetolunar.php php_datetolunar.h テスト

拡張機能をコンパイルするにはconfig.m4 ファイルを変更し、エビ行のコメント (つまり dnl) を削除します

PHP_ARG_WITH(datetolunar, for datetolunar support,

dnl コメントが整列していることを確認してください:

[ –with- datetolunar datetolunar サポートを含めます])

dnl それ以外の場合は、enable:

PHP_ARG_ENABLE(datetolunar, datetolunar サポートを有効にするかどうか,

dnl コメントが整列していることを確認してください:

[ –enable-datetolunar datetolunar サポートを有効にする])

外部 C ライブラリを参照しない場合は、あまり変更する必要はありません。それ以外の場合は、次の情報を知っておく必要があるかもしれません

PHP_ADD_INCLUDE

PHP_ADD_LIBRARY_WITH_PATH

PHP_SUBST

PHP_NEW_EXTENSION

具体的な使用方法については、Google で調べてください。

コンパイル

これで、この拡張機能を PHP にコンパイルできるようになります (ただし、機能はありません)。私は通常、動的コンパイル方法を選択します。簡単なため、ほとんどのオープンソース PHP 拡張機能にもこの方法を使用します。

~# phpize

~# ./configure –with-php-config=/opt/php/bin/php-config

~# make

~# make install

月の日付が生成されます。 so ファイルに extension=datetolunar.so を php.ini に追加すると、この拡張機能を呼び出すことができます。生成されたスケルトン コードには、拡張機能をテストして拡張機能が PHP に正常にコンパイルされたかどうかを確認する PHP ファイルが含まれています。

tiger➜php-5.6.17/ext/datetolunar» php datetolunar.php [14:31:26]

テスト拡張機能で利用可能な関数:

confirm_datetolunar_compiled

datetolunar

おめでとう成功しました! ext/datetolunar/config.m4 を修正しました。モジュール datetolunar が PHP にコンパイルされました。

C コードの作成

PHP 拡張機能の開発プロセスを紹介した後、太陰暦拡張機能を実装する方法を見てみましょう。まず、太陰暦のアルゴリズムについて一般的に理解する必要があるかもしれません。

旧暦アルゴリズムを理解する

旧暦計算の基礎知識

– アルゴリズムシリーズ No.20: 中国の旧暦の計算 (1)

– アルゴリズム シリーズ No.20: 中国の旧暦の計算 (2)

datetolunar.c を開く ファイルには、次の hex_lunar 定義が表示されます。

static int hex_lunar[] = {

0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,

0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2, 0x095b0,0,0x14977、

…。

};現在の年の閏年である場合は、閏月の月です。そうでない場合は、0 です。

5-16: 閏月を除く通常の月が大きい月か小さい月かを示します。1 は 30 日、0 は 29 日です。

注: 1 月から 12 月は 16 から 5 の位置に対応します。

17-20: 閏月が大きい月か小さい月かを示します。閏月がある場合にのみ意味を持ちます。

例:

1980 年のデータは次のとおりです: 0x095b0

バイナリ: 0000 1001 0101 1011 0000

は、1980 年には閏月がなく、1 月から 12 月までの日数は、30、29、29、30、29、30、29、30、30、29、30、30 であることを意味します。

1982 年のデータは: 0x0a974

0000 1010 0 1001 0111 0100

は、1982 年の 4 月が閏月であること、つまり 2 回目の 4 月があり、閏月であることを意味します。

1 月から 13 日までの日数は、30、29、30、29、29 (閏月)、30、29、29、30、29、30、30、30 です。

コーディングとデバッグ

PHP 拡張機能の作成を学び始めたばかりなので、あまり詳しくありません。まず関数の作成とデバッグを完了してから、コードを PHP 拡張機能にコピーすることにしました。 C言語のデバッグには、gdbよりもコードを見ながらデバッグできるcgdbの使用がおすすめです。

コンパイル

~# gcc -g lunar.c -o lunar

cgdb

を使用してデバッグする

~# sudo cgdb lunar

break – ブレークポイントを設定する

run – プログラムを実行する

print – 変数を出力する

continue - 実行を継続します

PS: 出力された配列が非常に長く、print が省略されている場合は、

>> set print element 0

によって gdb に設定できます。

コードが PHP 拡張機能に移行されます

C コードが記述され、問題がなければ、PHP 拡張機能に移行する準備をします。 ext_skel スクリプトを使用して以前に生成されたスケルトン コード datetolunar.c には、自動生成された C 関数 PHP_FUNCTION(datetolunar) の定義があります。

/* {{{ proto string datetolunar(int year, int month, int day)

; */

PHP_FUNCTION(datetolunar)

{

int argc = ZEND_NUM_ARGS();

long month;

長い一日;

if (zend_parse_parameters(argc TSRMLS_CC, “llll”, &year, &month, &day) == FAILURE)return;

php_error(E_WARNING, “datetolunar: まだ実装されていません”) ;

}

/* }}} */

関数によって渡されたパラメーターを取得するには、zend_parse_parameters() API 関数を使用できます。以下は、この関数のプロトタイプです:

zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, …);

最初のパラメータは、関数に渡されるパラメータの数です。通常のアプローチは、ZEND_NUM_ARGS() を渡すことです。これは、関数に渡される引数の合計数を表すマクロです。 2 番目のパラメータはスレッド セーフのため、常に TSRMLS_CC マクロを渡します。 3 番目のパラメーターは、関数で予期されるパラメーターのタイプを指定する文字列で、その後にパラメーター値で更新する必要がある変数のリストが続きます。 PHP は緩い変数定義と動的な型判定を使用するため、異なる型のパラメーターを期待される型に変換できます。たとえば、ユーザーが整数変数を渡しても、関数が浮動小数点数を必要とする場合、zend_parse_parameters() は整数を対応する浮動小数点数に自動的に変換します。実際の値を期待される型に変換できない場合 (整数から配列への変換など)、警告がトリガーされます。

これを理解したら、記述した C コードを関数にコピーします。私たちがしなければならないのは、PHP に必要な結果を返させることだけです。

PHP 関数からの戻り値

ここで文字列を返します。使用する関数は RETURN_STRING です

char* ret = lunar_output;RETVAL_STRINGL(lunar_output, strlen(ret), 1);

これは直接返されます静的な文字列、最後のパラメータが 0 に設定されている場合、PHP が文字列を解放するときにエラーが発生します。 PHP はタイプセーフなスクリプト言語であるため、PHP は RETURN_STRINGL または RETURN_STRING によって返された文字列を適切なタイミングで解放します。そのため、プログラマは返された文字列がヒープ内にあり、解放できることを確認する必要があります。これが動的割り当ての理由です。わかった。そして:

char* ret = “hello world”;RETURN_STRINGL(ret, strlen(ret), 0);

これは静的文字列を直接返すため、この文字列を解放するときに PHP でエラーが発生します。 RETURN_STRINGL と RETURN_STRING の最後のパラメータが 1 の場合、最初のパラメータの文字列のコピーがヒープに返されることを意味するため、問題はありません。

拡張機能 API には、関数から値を返すための豊富なマクロが含まれています。これらのマクロには主に 2 つの種類があります。 1 つ目は RETVAL_type() 形式で、戻り値を設定しますが、C コードは実行を継続します。これは通常、スクリプト エンジンに制御を渡す前にクリーンアップ作業を行い、C の return ステートメント「return」を使用して PHP に戻る場合に使用されます。後者のマクロの方が一般的で、その形式は RETURN_type() です。戻り値の型が設定され、制御が PHP に返されます。次の表では、存在するほとんどのマクロについて説明します。

RETURN_BOOL(b)RETVAL_BOOL( b)ブール値 (1 または 0)RETURN_NULL()RETVAL_NULL()NULLRETURN_DOUBLE(d)RETVAL_DOUBLE(d) 浮動小数点数RETURN_STRING(s, dup)RETVAL_STRING(s, dup)文字列。 dup が 1 の場合、エンジンはコピーを使用して estrdup() を呼び出して を繰り返します。 dup が 0 の場合、 sRETURN_STRINGL(s, l, dup)RETVAL_STRINGL(s, l, dup) 長さ l の文字列値を使用します。前のマクロと同じですが、 s の長さが指定されているため、より速くなります。 RETURN_TRUERETVAL_TRUEブール値 true を返します。このマクロには括弧がないことに注意してください。 RETURN_FALSERETVAL_FALSEブール値 false を返します。このマクロには括弧がないことに注意してください。 RETURN_RESOURCE(r)RETVAL_RESOURCE(r)リソースハンドル。
戻り値を設定して関数を終了する 戻り値を設定する マクロの戻り値の型とパラメータ
RETURN_LONG(l) RETVAL_LONG(l) 整数
作業完了

これで、PHP 旧暦拡張機能が完成しました。コンパイルが成功しました! ! ! (もちろん作るときに問題が起きるかもしれないので一つ一つ解決していきましょう)

テストしてみよう

tiger➜work/github/php-lunar-extension» php -r "echo datetolunar(2016,2,27); " [ 14:47:19]Bingshen [Monkey] 20% of the first month

OK、Good~

パフォーマンステスト

同じ機能を実装する旧暦変換コード。 1 つ目は PHP に実装した旧暦機能、2 つ目は実装したばかりの PHP 拡張機能で、どちらも 10,000 回実行され、パフォーマンスが約 86 倍向上しました (ちょっと興奮しました〜)。

tiger➜work/github/php-lunar-extension» php test.php [18:28:06]

>> php 拡張機能を実行します。

1.7234871387482

>>

0.022943019866943

拡張コードはここにあります: https://github.com/jixiaod/php-lunar-extension

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