Resumen de la primera parte
En la
primera parte, puse una extensión en blanco, la hice funcionar correctamente en Clion IDE, escribí una función analógica, my_array_fill (), y verifiqué su operatividad en php.
Que ahora
Ahora voy a poner el
código de la biblioteca libtrie en nuestra extensión.
Hablaré un poco sobre cómo puede hacer que las antiguas extensiones php5 funcionen en php7.
Además, haré algunas funciones básicas de esta biblioteca en php y comprobaré qué sucedió.
Vamos
Obtenga el código libtrie en nuestra extensión
Voy al directorio de extensiones
cd ~/Documents/libtrie/
Clonando el repositorio libtrie
git clone https:

Abro el archivo con el código de extensión
php_libtrie.c
y el archivo con el código de biblioteca
libtrie/src/libtrie.c
.

Usaré este último para verificar los nombres y la sintaxis de las funciones.
Las funciones creadas en php que usaré son las mismas que en la biblioteca misma.
En primer lugar, debe incluir el archivo de encabezado de la biblioteca en el código de nuestra extensión.
Escribimos en php_libtrie.c:
#include "libtrie/src/libtrie.h"
Función Yatrie_new
Hago la primera función que creará el árbol de prefijos. En la biblioteca se llama
trie_s *yatrie_new(uint32_t max_nodes, uint32_t max_refs, uint32_t max_deallocated_size) {...}
Como puede ver en el código, la función toma 3 argumentos numéricos en la entrada y devuelve un puntero a la estructura
trie_s
. En pocas palabras, devuelve un enlace al árbol de prefijos creado.
Para extraer nuestro árbol de prefijos a PHP, PHP tiene un tipo de datos de recursos especial. Cuando una función se ejecuta en PHP
fopen("filename.ext");
Hablando en lenguaje C, el programa le pide al sistema operativo que abra el archivo especificado, crea un puntero a este archivo, que en forma de recurso y regresa a PHP.
Haremos lo mismo con nuestro árbol.
Hagamos una función en php_libtrie.c:
Código de función 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)); }
Ahora necesita agregar la función creada a la matriz de funciones de extensión, de lo contrario, la función no será visible desde PHP.
PHP_FE(yatrie_new, NULL)

Para que se vea hermoso, agregaré una declaración de función al archivo de encabezado. Esto no es necesario, ya que nuestras funciones PHP no interactúan entre sí, pero aún así prefiero declarar todas las funciones en el archivo de encabezado.
Solo agrega las líneas:
PHP_FUNCTION(confirm_libtrie_compiled)
al archivo php_libtrie.h. En cualquier lugar entre:
#ifndef PHP_LIBTRIE_H #define PHP_LIBTRIE_H
y
#endif

PHP creado destructor de recursos
La función yatrie_new () creada crea un árbol y también registra un recurso PHP. Ahora necesitamos una función que cierre el recurso creado y libere la memoria ocupada por el árbol de prefijos.
static void php_libtrie_dtor(zend_resource *rsrc TSRMLS_DC) {
Como la función es interna a la matriz de funciones de extensión, no está incluida. Agregue su declaración a php_libtrie.h:

Ahora necesita registrar la función destructora creada en PHP. Esto se hace a través de una función especial de inicialización de extensión. Antes de esto, esta función simplemente devolvía el ÉXITO inmediatamente. Es necesario agregar allí el registro del destructor.
// 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; }

Eliminar la función de árbol creada
Así como la función
fopen()
tiene un par de
fclose()
, la función de creación de mi árbol debería tener una novia que lo 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; }
Agregue una función a la matriz de funciones de extensión:
PHP_FE(yatrie_free, NULL)
Agregue la declaración de función al archivo de encabezado:
PHP_FUNCTION(yatrie_free)

Como puede ver en la captura de pantalla, agregué el nombre interno del recurso en PHP al archivo de encabezado, así como las macros PHP5, que por alguna razón se eliminaron de PHP7. No los uso, pero si alguien quiere hacerlo, puede construir fácilmente la extensión PHP5 a PHP7.
#define PHP_LIBTRIE_VERSION "0.1.0" #define PHP_LIBTRIE_RES_NAME "libtrie data structure"
Función agregar palabras en trie
Ahora hagamos la función de agregar una palabra al árbol de prefijos.
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); }
- Agregue una entrada a la matriz de funciones:
PHP_FE(yatrie_add, NULL)
- Agregue una declaración al archivo de encabezado:
PHP_FUNCTION(yatrie_add)
La función para generar todas las palabras del diccionario
Ahora hagamos una función que seleccionará todas las palabras del árbol de prefijos y las generará en PHP como una 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); }
- Agregue una entrada a la matriz de funciones:
PHP_FE(node_traverse, NULL)
- Agregue una declaración al archivo de encabezado:
PHP_FUNCTION(node_traverse)
Conjunto de extensión
Dado que la extensión ahora usa archivos de biblioteca de terceros, estos archivos también deben compilarse. Abro el archivo config.m4 y agrego los 2 archivos fuente de libtrie allí:
libtrie/src/libtrie.c
libtrie/src/single_list.c
Aquí está el contenido completo del archivo después de los cambios.
config.m4 PHP_ARG_ENABLE(libtrie, whether to enable libtrie support, [ --enable-libtrie Enable libtrie support]) if test "$PHP_LIBTRIE" != "no"; then

Ahora necesita volver a hacer el script ./configure. Corro desde el directorio raíz de la extensión:
phpize && ./configure
Ahora estoy construyendo la extensión:
make
Prueba
Para la prueba, es mejor hacer un script php para no escribir mucho en la consola. Haré esto:
nano yatrie_test.php
Y este es el contenido del archivo:
<?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);
Ejecutamos en la consola:
php -d extension=modules/libtrie.so yatrie_test.php
Esto es lo que debes obtener:

Tomamos el código fuente de la extensión
desde aquí . No seas tímido y pon asteriscos :-)