Resumo da primeira parte
Na
primeira parte, deixei uma extensão em branco, fiz funcionar corretamente no Clion IDE, escrevi uma função análoga a my_array_fill () e verifiquei sua operabilidade no php.
O que agora
Agora vou colocar o
código da biblioteca libtrie em nossa extensão.
Falarei um pouco sobre como você pode fazer com que extensões antigas do php5 funcionem no php7.
Além disso, farei algumas funções básicas desta biblioteca em php e verificarei o que aconteceu.
Vamos lá
Obtenha código libtrie em nossa extensão
Eu vou para o diretório de extensão
cd ~/Documents/libtrie/
Clonando o repositório libtrie
git clone https:

Abro o arquivo com o código de extensão
php_libtrie.c
e o arquivo com o código da biblioteca
libtrie/src/libtrie.c
.

Usarei o último para verificar os nomes e a sintaxe das funções.
As funções criadas no php que utilizarei são as mesmas da própria biblioteca.
Primeiro de tudo, você precisa incluir o arquivo de cabeçalho da biblioteca no código da nossa extensão.
Escrevemos em php_libtrie.c:
#include "libtrie/src/libtrie.h"
Função Yatrie_new
Eu faço a primeira função que criará a árvore de prefixos. Na biblioteca é chamado
trie_s *yatrie_new(uint32_t max_nodes, uint32_t max_refs, uint32_t max_deallocated_size) {...}
Como você pode ver no código, a função pega 3 argumentos numéricos na entrada e retorna um ponteiro para a estrutura
trie_s
. Simplificando, retorna um link para a árvore de prefixos criada.
Para inserir nossa árvore de prefixos no PHP, o PHP possui um tipo de dados de recurso especial. Quando uma função é executada em PHP
fopen("filename.ext");
Falando na linguagem C, o programa solicita ao sistema operacional que abra o arquivo especificado, cria um ponteiro para esse arquivo, que na forma de um recurso e retorna para o PHP fora.
Faremos o mesmo com a nossa árvore.
Vamos criar uma função em php_libtrie.c:
Código de função 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)); }
Agora você precisa adicionar a função criada à matriz de funções de extensão, caso contrário, a função não será visível no PHP.
PHP_FE(yatrie_new, NULL)

Para torná-la bonita, adicionarei uma declaração de função ao arquivo de cabeçalho. Isso não é necessário, pois nossas funções PHP não interagem umas com as outras, mas ainda prefiro declarar todas as funções no arquivo de cabeçalho.
Basta adicionar as linhas:
PHP_FUNCTION(confirm_libtrie_compiled)
para o arquivo php_libtrie.h. Em qualquer lugar entre:
#ifndef PHP_LIBTRIE_H #define PHP_LIBTRIE_H
e
#endif

Destruidor de recursos criado pelo PHP
A função yatrie_new () criada cria uma árvore e também registra um recurso PHP. Agora precisamos de uma função que feche o recurso criado e libere a memória ocupada pela árvore de prefixos.
static void php_libtrie_dtor(zend_resource *rsrc TSRMLS_DC) {
Como a função é interna à matriz de funções de extensão, ela não está incluída. Adicione a declaração dela ao php_libtrie.h:

Agora você precisa registrar a função destruidora criada no PHP. Isso é feito através de uma função especial de inicialização de extensão. Antes disso, essa função simplesmente retornava SUCESSO imediatamente. É necessário adicionar lá o registro do destruidor.
// 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; }

Excluir função de árvore criada
Assim como a função
fopen()
possui algumas funções
fclose()
, minha função de criação de árvore deve ter uma namorada que a equilibre.
Código /** * @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; }
Adicione uma função à matriz de funções de extensão:
PHP_FE(yatrie_free, NULL)
Adicione a declaração da função ao arquivo de cabeçalho:
PHP_FUNCTION(yatrie_free)

Como você pode ver na captura de tela, adicionei o nome interno do recurso no PHP ao arquivo de cabeçalho, bem como as macros do PHP5, que por algum motivo foram removidas do PHP7. Eu não os uso, mas se alguém quiser, você pode facilmente criar a extensão PHP5 para PHP7.
#define PHP_LIBTRIE_VERSION "0.1.0" #define PHP_LIBTRIE_RES_NAME "libtrie data structure"
Função adicionar palavras em trie
Agora vamos fazer a função de adicionar uma palavra à árvore de prefixos.
Código /** * @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); }
- Adicione uma entrada à matriz de funções:
PHP_FE(yatrie_add, NULL)
- Adicione uma declaração ao arquivo de cabeçalho:
PHP_FUNCTION(yatrie_add)
A função para gerar todas as palavras do dicionário
Agora vamos criar uma função que selecionará todas as palavras da árvore de prefixos e as produzirá em PHP como uma matriz.
Código /** * @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); }
- Adicione uma entrada à matriz de funções:
PHP_FE(node_traverse, NULL)
- Adicione uma declaração ao arquivo de cabeçalho:
PHP_FUNCTION(node_traverse)
Conjunto de extensão
Como a extensão agora usa arquivos de biblioteca de terceiros, esses arquivos também devem ser compilados. Abro o arquivo config.m4 e adiciono os 2 arquivos de origem libtrie:
libtrie/src/libtrie.c
libtrie/src/single_list.c
Aqui está o conteúdo completo do arquivo após as alterações.
config.m4 PHP_ARG_ENABLE(libtrie, whether to enable libtrie support, [ --enable-libtrie Enable libtrie support]) if test "$PHP_LIBTRIE" != "no"; then

Agora você precisa refazer o script ./configure. Eu corro a partir do diretório raiz da extensão:
phpize && ./configure
Agora estou construindo a extensão:
make
Teste
Para o teste, é melhor criar um script php para não escrever muito no console. Eu farei isso:
nano yatrie_test.php
E este é o conteúdo do arquivo:
<?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);
Executamos no console:
php -d extension=modules/libtrie.so yatrie_test.php
Aqui está o que você deve obter:

Nós pegamos o código fonte da extensão
daqui . Não seja tímido e coloque asteriscos :-)