前半のまとめ
最初の部分では、拡張機能を空白にし、Clion IDEで正しく機能させ、アナログ関数my_array_fill()を作成し、phpでその操作性を確認しました。
今何
次に、libtrieライブラリコードを拡張機能に追加します。
古いphp5拡張機能をphp7で機能させる方法について少しお話しします。
さらに、このライブラリからいくつかの基本的な関数をPHPで作成し、何が起こったのかを確認します。
行こう
拡張機能でlibtrieコードを取得する
拡張機能ディレクトリに移動します
cd ~/Documents/libtrie/
libtrieリポジトリの複製
git clone https://github.com/legale/libtrie
拡張子コード
php_libtrie.c
のファイルと、ライブラリコード
libtrie/src/libtrie.c
のファイルを
libtrie/src/libtrie.c
ます。
後者を使用して、関数の名前と構文を確認します。
使用するphpで作成される関数は、ライブラリ自体と同じです。
まず、ライブラリヘッダーファイルを拡張機能のコードに含める必要があります。
php_libtrie.cに書き込みます。
#include "libtrie/src/libtrie.h"
Yatrie_new関数
プレフィックスツリーを作成する最初の関数を作成します。 図書館では、
trie_s *yatrie_new(uint32_t max_nodes, uint32_t max_refs, uint32_t max_deallocated_size) {...}
コードからわかるように、関数は入力で3つの数値引数を受け入れ、
trie_s
構造体へのポインターを返します。 簡単に言えば、作成されたプレフィックスツリーへのリンクを返します。
プレフィックスツリーをPHPに取り込むために、PHPには特別なデータ型リソースがあります。 PHPで関数が実行されるとき
fopen("filename.ext");
C言語で話すと、プログラムはオペレーティングシステムに指定されたファイルを開くように要求し、このファイルへのポインターを作成します。これはリソースの形式で、PHPの外部に戻ります。
同じことをツリーで行います。
php_libtrie.cで関数を作成しましょう:
機能コード
PHP_FUNCTION (yatrie_new) { /* */ trie_s *trie; // zend_long max_nodes; // - zend_long max_refs; /* - . * . - +25% . * , OpenCorpora ~3. 5. 5. */ zend_long max_deallocated_size; /* * . 96 , 1 , 95. * 95, , * . 94. */ // PHP if (zend_parse_parameters(ZEND_NUM_ARGS(), "lll", &max_nodes, &max_refs, &max_deallocated_size) == FAILURE) { RETURN_FALSE; } // trie = yatrie_new((uint32_t)max_nodes, (uint32_t)max_refs, (uint32_t)max_deallocated_size); // - if (!trie) { RETURN_NULL(); } // 2 /* zend_register_resource() Zend, * le_libtrie, ZVAL_RES() * zval return_value */ ZVAL_RES(return_value, zend_register_resource(trie, le_libtrie)); }
次に、作成した関数を拡張関数の配列に追加する必要があります。追加しないと、関数はPHPから見えなくなります。
PHP_FE(yatrie_new, NULL)
美しく見せるために、ヘッダーファイルに関数宣言を追加します。 PHPの関数は相互に作用しないため、これは必要ありませんが、ヘッダーファイルですべての関数を宣言することを好みます。
行を追加するだけです:
PHP_FUNCTION(confirm_libtrie_compiled); PHP_FUNCTION(my_array_fill); PHP_FUNCTION(yatrie_new);
php_libtrie.hファイルに。 間のどこでも:
#ifndef PHP_LIBTRIE_H #define PHP_LIBTRIE_H
そして
#endif /* PHP_LIBTRIE_H */
PHPが作成したリソースデストラクター
作成されたyatrie_new()関数はツリーを作成し、PHPリソースも登録します。 次に、作成されたリソースを閉じて、プレフィックスツリーが占有していたメモリを解放する関数が必要です。
/** * @brief , * @param rsrc : zend_resource * * @return void */ static void php_libtrie_dtor(zend_resource *rsrc TSRMLS_DC) { // trie trie_s *trie = (trie_s *) rsrc->ptr; // , , // trie yatrie_free(trie); }
関数は拡張関数の配列の内部にあるため、含まれていません。 php_libtrie.hに彼女の宣言を追加します。
次に、作成したデストラクタ関数をPHPに登録する必要があります。 これは、特別な拡張機能初期化関数を介して行われます。 これに先立ち、この関数は単にSUCCESSをすぐに返しました。 デストラクタの登録をそこに追加する必要があります。
// PHP trie PHP_MINIT_FUNCTION (libtrie) { le_libtrie = zend_register_list_destructors_ex( php_libtrie_dtor, NULL, PHP_LIBTRIE_RES_NAME, module_number); return SUCCESS; }
作成されたツリー関数を削除
fopen()
関数に
fclose()
いくつかあるのと同じように、ツリー作成関数には、バランスを取るガールフレンドが必要です。
コード
/** * @brief * @param trie : resource * @return true/false : bool */ PHP_FUNCTION (yatrie_free) { zval *resource; // zval // if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &resource) == FAILURE) { RETURN_FALSE; } /* , zend_resource, * zval. Z_RES_P() */ if (zend_list_close(Z_RES_P(resource)) == SUCCESS) { // true return_vale return RETURN_TRUE; } // false return_vale return RETURN_FALSE; }
拡張関数の配列に関数を追加します。
PHP_FE(yatrie_free, NULL)
関数宣言をヘッダーファイルに追加します。
PHP_FUNCTION(yatrie_free);
スクリーンショットでわかるように、PHPのリソースの内部名をヘッダーファイルに追加しました。PHP5マクロは、何らかの理由でPHP7から削除されました。 私はそれらを使用しませんが、誰かがそれらを使いたい場合は、PHP7へのPHP5拡張モジュールを簡単に構築できます。
#define PHP_LIBTRIE_VERSION "0.1.0" /* Replace with version number for your extension */ #define PHP_LIBTRIE_RES_NAME "libtrie data structure" /* PHP resource name */ //previously (php5) used MACROS #define ZEND_FETCH_RESOURCE(rsrc, rsrc_type, passed_id, default_id, resource_type_name, resource_type) \ (rsrc = (rsrc_type) zend_fetch_resource(Z_RES_P(*passed_id), resource_type_name, resource_type)) #define ZEND_REGISTER_RESOURCE(return_value, result, le_result) ZVAL_RES(return_value,zend_register_resource(result, le_result))
トライに単語を追加する関数
それでは、プレフィックスツリーに単語を追加する機能を作成しましょう。
-
コード/** * @brief trie node_id * @param trie : resource * @param word : string * @return node_id : int */ PHP_FUNCTION (yatrie_add) { trie_s *trie; // zval *resource; // zval unsigned char *word = NULL; // size_t word_len; // word uint32_t node_id; //id , // if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &resource, &word, &word_len) == FAILURE) { RETURN_FALSE } /* PHP, : * 1 PHP ( zval, ), * 2 * * 3 id , * void *, trie_s * * PHP5 ZEND_FETCH_RESOURCE(), - PHP7. */ trie = (trie_s *) zend_fetch_resource(Z_RES_P(resource), PHP_LIBTRIE_RES_NAME, le_libtrie); /* trie * - * - id , * - . */ node_id = yatrie_add(word, 0, trie); // RETURN_LONG(node_id); }
- 関数の配列にエントリを追加します。
PHP_FE(yatrie_add, NULL)
- ヘッダーファイルに宣言を追加します。
PHP_FUNCTION(yatrie_add)
辞書からすべての単語を出力する関数
次に、プレフィックスツリーからすべての単語を選択し、PHPで配列として出力する関数を作成しましょう。
-
コード/** * @brief , , * , * @param trie : resource * @param node_id : int * @param head () : string , * * @return array */ PHP_FUNCTION (node_traverse) { trie_s *trie; // trie words_s *words; // trie zval * resource; // zval zend_long node_id; // unsigned char *head = NULL; // size_t head_len; // // PHP if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|s", &resource, &node_id, &head, &head_len) == FAILURE) { RETURN_NULL(); // null } // trie = (trie_s *) zend_fetch_resource(Z_RES_P(resource), PHP_LIBTRIE_RES_NAME, le_libtrie); // trie node_traverse() words_s // words = (words_s *) calloc(1, sizeof(words_s)); words->counter = 0; // 0 // 1 string_s *head_libtrie = calloc(1, sizeof(string_s)); // head if(head != NULL) { head_libtrie->length = (uint32_t)head_len; // memcpy(&head_libtrie->letters, head, head_len); // head_libtrie } // trie node_traverse(words, (uint32_t) node_id, head_libtrie, trie); // PHP , words array_init_size(return_value, words->counter); // php while (words->counter--) { // trie , // uint8_t dst[256]; // libtrie decode_string(dst, words->words[words->counter]); // Zend API, php string char * add_next_index_string(return_value, (const char *) dst); } // words head_libtrie free(words); free(head_libtrie); }
- 関数の配列にエントリを追加します。
PHP_FE(node_traverse, NULL)
- ヘッダーファイルに宣言を追加します。
PHP_FUNCTION(node_traverse)
拡張アセンブリ
拡張機能はサードパーティのライブラリファイルを使用するようになったため、これらのファイルもコンパイルする必要があります。 config.m4ファイルを開き、そこに2つのlibtrieソースファイルを追加します。
libtrie/src/libtrie.c
libtrie/src/single_list.c
変更後のファイルの完全な内容は次のとおりです。
config.m4
PHP_ARG_ENABLE(libtrie, whether to enable libtrie support, [ --enable-libtrie Enable libtrie support]) if test "$PHP_LIBTRIE" != "no"; then # - # PHP_ADD_INCLUDE(libtrie/src/) # PHP_NEW_EXTENSION(libtrie, \ libtrie/src/libtrie.c \ libtrie/src/single_list.c \ php_libtrie.c \ , $ext_shared) # PHP_NEW_EXTENSION(libtrie, php_libtrie.c libtrie/src/libtrie.c libtrie/src/single_list.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) fi
ここで、。/ configureスクリプトを再実行する必要があります。 拡張機能のルートディレクトリから開始します。
phpize && ./configure
今、私は拡張機能を構築しています:
make
テスト中
テストでは、コンソールにあまり記述しないようにphpスクリプトを作成するのが最適です。 これを行います:
nano yatrie_test.php
そして、これはファイルの内容です:
<?php echo "C 500 500 \n\n"; $trie = yatrie_new(500, 500, 100); echo "!\n , id \$nodes\n"; $nodes[] = yatrie_add($trie, ""); $nodes[] = yatrie_add($trie, ""); $nodes[] = yatrie_add($trie, ""); echo " .\n 2 , 2.\n 3 , 2 ,\n 1 \n"; print_r($nodes); print_r(node_traverse($trie, 0)); yatrie_free($trie);
コンソールで実行します:
php -d extension=modules/libtrie.so yatrie_test.php
取得する必要があるものは次のとおりです。
結果の拡張ソースコードは、ここから取得されます 。 恥ずかしがらずにアスタリスクを入れないでください:-)