ملخص الجزء الأول
في
الجزء الأول ، قمت بعمل ملحق فارغ ، وجعلته يعمل بشكل صحيح في 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. يتم ذلك من خلال وظيفة التهيئة الخاصة بالامتداد. قبل ذلك ، أعادت هذه الوظيفة النجاح على الفور. من الضروري إضافة تسجيل المدمر هناك.
// 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 وأضيف ملفات المصدر libtrie 2 هناك:
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

الآن أنت بحاجة إلى إعادة تنفيذ ./configure script. أركض من الدليل الجذر للملحق:
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
إليك ما يجب أن تحصل عليه:

نأخذ كود المصدر للإضافة
من هنا . لا تخجل وتضع العلامات النجمية :-)