第一部分摘要
在
第一部分中,我将扩展名留为空白,使其在Clion IDE中正常工作,编写了类似于my_array_fill()的函数,并在php中检查了其可操作性。
现在呢
现在,我将把libtrie库
代码放入我们的扩展中。
我将讨论如何使旧的php5扩展在php7中工作。
此外,我将从php中的该库中获取一些基本功能,并检查发生了什么。
走吧
在我们的扩展中获取libtrie代码
我进入扩展目录
cd ~/Documents/libtrie/
克隆libtrie存储库
git clone https:

我打开扩展名为
php_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_libtrie.h文件。 之间的任何位置:
#ifndef PHP_LIBTRIE_H #define PHP_LIBTRIE_H
和
#endif

PHP创建的资源析构函数
创建的yatrie_new()函数创建一棵树,并注册一个PHP资源。 现在我们需要一个函数,该函数将关闭创建的资源并释放前缀树占用的内存。
static void php_libtrie_dtor(zend_resource *rsrc TSRMLS_DC) {
由于该功能是扩展功能数组的内部功能,因此不包括在内。 将她的声明添加到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中删除)添加到头文件中。 我不使用它们,但是如果有人愿意使用它们,则可以轻松地将PHP5扩展构建为PHP7。
#define PHP_LIBTRIE_VERSION "0.1.0" #define PHP_LIBTRIE_RES_NAME "libtrie data structure"
功能在特里添加单词
现在,让我们执行将单词添加到前缀树的功能。
代号 /** * @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
这是更改后文件的全部内容。
配置文件 PHP_ARG_ENABLE(libtrie, whether to enable libtrie support, [ --enable-libtrie Enable libtrie support]) if test "$PHP_LIBTRIE" != "no"; then

现在,您需要重新执行./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
这是您应该得到的:

我们
从这里获取扩展的源代码。 不要害羞,并加星号:-)