Zusammenfassung des ersten Teils
Im
ersten Teil habe ich eine Erweiterung leer gemacht, sie in der Clion-IDE korrekt funktionieren lassen, eine analoge Funktion, my_array_fill (), geschrieben und ihre Funktionsfähigkeit in PHP überprüft.
Was jetzt?
Jetzt werde ich den libtrie-Bibliothekscode in unsere Erweiterung
einfügen .
Ich werde ein wenig darüber sprechen, wie Sie alte PHP5-Erweiterungen in PHP7 zum Laufen bringen können.
Weiter werde ich einige Grundfunktionen aus dieser Bibliothek in PHP machen und überprüfen, was passiert ist.
Lass uns gehen
Holen Sie sich libtrie Code in unserer Erweiterung
Ich gehe in das Erweiterungsverzeichnis
cd ~/Documents/libtrie/
Klonen des libtrie-Repositorys
git clone https:

Ich öffne die Datei mit dem Erweiterungscode
php_libtrie.c
und die Datei mit dem Bibliothekscode
libtrie/src/libtrie.c
.

Ich werde letzteres verwenden, um die Namen und die Syntax von Funktionen zu überprüfen.
Die in PHP erstellten Funktionen, die ich verwenden werde, sind die gleichen wie in der Bibliothek selbst.
Zunächst müssen Sie die Bibliotheks-Header-Datei in den Code unserer Erweiterung aufnehmen.
Wir schreiben in php_libtrie.c:
#include "libtrie/src/libtrie.h"
Yatrie_new Funktion
Ich mache die erste Funktion, die den Präfixbaum erstellt. In der Bibliothek heißt es
trie_s *yatrie_new(uint32_t max_nodes, uint32_t max_refs, uint32_t max_deallocated_size) {...}
Wie Sie dem Code
trie_s
können, verwendet die Funktion 3 numerische Argumente am Eingang und gibt einen Zeiger auf die Struktur
trie_s
. Einfach ausgedrückt, gibt einen Link zum erstellten Präfixbaum zurück.
Um unseren Präfixbaum in PHP zu ziehen, verfügt PHP über einen speziellen Ressourcendatentyp. Wenn eine Funktion in PHP ausgeführt wird
fopen("filename.ext");
In C-Sprache fordert das Programm das Betriebssystem auf, die angegebene Datei zu öffnen, erstellt einen Zeiger auf diese Datei, die in Form einer Ressource vorliegt und außerhalb von PHP zurückgegeben wird.
Wir werden dasselbe mit unserem Baum tun.
Machen wir eine Funktion in php_libtrie.c:
Funktionscode 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)); }
Jetzt müssen Sie die erstellte Funktion zum Array der Erweiterungsfunktionen hinzufügen, da die Funktion sonst in PHP nicht sichtbar ist.
PHP_FE(yatrie_new, NULL)

Damit es schön aussieht, füge ich der Header-Datei eine Funktionsdeklaration hinzu. Dies ist nicht erforderlich, da unsere PHP-Funktionen nicht miteinander interagieren, aber ich bevorzuge es dennoch, alle Funktionen in der Header-Datei zu deklarieren.
Fügen Sie einfach die Zeilen hinzu:
PHP_FUNCTION(confirm_libtrie_compiled)
in die Datei php_libtrie.h. Überall zwischen:
#ifndef PHP_LIBTRIE_H #define PHP_LIBTRIE_H
und
#endif

PHP hat einen Ressourcenzerstörer erstellt
Die erstellte Funktion yatrie_new () erstellt einen Baum und registriert auch eine PHP-Ressource. Jetzt brauchen wir eine Funktion, die die erstellte Ressource schließt und den vom Präfixbaum belegten Speicher frei macht.
static void php_libtrie_dtor(zend_resource *rsrc TSRMLS_DC) {
Da die Funktion innerhalb des Arrays der Erweiterungsfunktionen liegt, ist sie nicht enthalten. Fügen Sie ihre Erklärung zu php_libtrie.h hinzu:

Jetzt müssen Sie die erstellte Destruktorfunktion in PHP registrieren. Dies erfolgt über eine spezielle Erweiterungsinitialisierungsfunktion. Zuvor hat diese Funktion einfach sofort SUCCESS zurückgegeben. Dort muss die Registrierung des Destruktors hinzugefügt werden.
// 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; }

Löschen Sie die erstellte Baumfunktion
So wie die Funktion
fopen()
ein paar
fclose()
, sollte meine
fclose()
eine Freundin haben, die das ausgleicht.
Code /** * @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; }
Fügen Sie dem Array der Erweiterungsfunktionen eine Funktion hinzu:
PHP_FE(yatrie_free, NULL)
Fügen Sie der Header-Datei die Funktionsdeklaration hinzu:
PHP_FUNCTION(yatrie_free)

Wie Sie im Screenshot sehen können, habe ich der Header-Datei den internen Namen der Ressource in PHP sowie die PHP5-Makros hinzugefügt, die aus irgendeinem Grund aus PHP7 entfernt wurden. Ich benutze sie nicht, aber wenn jemand mit ihnen will, können Sie einfach die PHP5-Erweiterung auf PHP7 bauen.
#define PHP_LIBTRIE_VERSION "0.1.0" #define PHP_LIBTRIE_RES_NAME "libtrie data structure"
Funktion füge Wörter in trie hinzu
Lassen Sie uns nun die Funktion ausführen, dem Präfixbaum ein Wort hinzuzufügen.
Code /** * @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); }
- Fügen Sie dem Funktionsfeld einen Eintrag hinzu:
PHP_FE(yatrie_add, NULL)
- Fügen Sie der Header-Datei eine Deklaration hinzu:
PHP_FUNCTION(yatrie_add)
Die Funktion zum Ausgeben aller Wörter aus dem Wörterbuch
Lassen Sie uns nun eine Funktion erstellen, die alle Wörter aus dem Präfixbaum auswählt und sie in PHP als Array ausgibt.
Code /** * @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); }
- Fügen Sie dem Funktionsfeld einen Eintrag hinzu:
PHP_FE(node_traverse, NULL)
- Fügen Sie der Header-Datei eine Deklaration hinzu:
PHP_FUNCTION(node_traverse)
Erweiterungsbaugruppe
Da die Erweiterung jetzt Bibliotheksdateien von Drittanbietern verwendet, müssen diese Dateien ebenfalls kompiliert werden. Ich öffne die Datei config.m4 und füge dort die 2 libtrie-Quelldateien hinzu:
libtrie/src/libtrie.c
libtrie/src/single_list.c
Hier ist der vollständige Inhalt der Datei nach den Änderungen.
config.m4 PHP_ARG_ENABLE(libtrie, whether to enable libtrie support, [ --enable-libtrie Enable libtrie support]) if test "$PHP_LIBTRIE" != "no"; then

Jetzt müssen Sie das Skript ./configure erneut ausführen. Ich starte aus dem Stammverzeichnis der Erweiterung:
phpize && ./configure
Jetzt baue ich die Erweiterung:
make
Testen
Für den Test ist es am besten, ein PHP-Skript zu erstellen, um nicht viel in die Konsole zu schreiben. Ich werde das tun:
nano yatrie_test.php
Und das ist der Inhalt der Datei:
<?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);
Wir führen in der Konsole aus:
php -d extension=modules/libtrie.so yatrie_test.php
Folgendes sollten Sie bekommen:

Wir nehmen den Quellcode der Erweiterung
von hier . Sei nicht schüchtern und setze Sternchen :-)