PHP7の拡張機能を「hello、world」よりも難しくし、目立たないようにする方法。 パート2

前半のまとめ



最初の部分では、拡張機能を空白にし、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))
      
      





トライに単語を追加する関数



それでは、プレフィックスツリーに単語を追加する機能を作成しましょう。





  1. コード
     /** * @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); }
          
          







  2. 関数の配列にエントリを追加します。



     PHP_FE(yatrie_add, NULL)
          
          



  3. ヘッダーファイルに宣言を追加します。



     PHP_FUNCTION(yatrie_add)
          
          





辞書からすべての単語を出力する関数



次に、プレフィックスツリーからすべての単語を選択し、PHPで配列として出力する関数を作成しましょう。





  1. コード
     /** * @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); }
          
          





  2. 関数の配列にエントリを追加します。



     PHP_FE(node_traverse, NULL)
          
          





  3. ヘッダーファイルに宣言を追加します。



     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
      
      





取得する必要があるものは次のとおりです。







結果の拡張ソースコードは、ここから取得されます 。 恥ずかしがらずにアスタリスクを入れないでください:-)



All Articles