Mengapa
Saya menulis artikel ini sehingga jalur yang saya ambil total setidaknya satu tahun, pembaca bisa berjalan dalam beberapa jam. Seperti yang ditunjukkan oleh pengalaman pribadi saya, hanya pemrograman dalam C sedikit lebih mudah daripada membuat ekstensi serius untuk pekerjaan PHP. Di sini saya akan memberi tahu Anda sebanyak mungkin tentang cara membuat ekstensi menggunakan contoh perpustakaan
libtrie yang mengimplementasikan pohon awalan, lebih dikenal sebagai trie. Saya akan menulis dan secara bersamaan melakukan tindakan yang dijelaskan pada sistem Lubuntu 18.04 yang baru diinstal.
Mari kita mulai.
Instalasi perangkat lunak
Php
- Pertama kita meletakkan paket php7.2-dev, di dalamnya diperlukan skrip phpize untuk membangun ekstensi. Selain itu, kita membutuhkan versi php yang berfungsi, di mana kita akan memeriksa ekstensi kita. Menginstal paket ini akan menarik sejumlah paket tergantung, kami meletakkan semua yang ditawarkan.
sudo apt install php7.2-dev
- Kami pergi ke situs web php.net, pergi ke bagian unduhan dan menarik tautan ke arsip dengan versi stabil terbaru dari php, sekarang versi 7.2.11.
Unduh arsip sumber php:
cd /tmp && wget http://it2.php.net/get/php-7.2.11.tar.gz/from/this/mirror -O php7.tar.gz
- Sekarang buka arsipnya sendiri:
sudo tar -xvf php7.tar.gz -C /usr/local/src
Editor Kode
Saya biasanya menggunakan 2 editor kode. Simpel dan cepat, cepat, dan sangat kutu buku, tetapi sangat canggih dari JetBrains. Geany menginstal dari lobak standar Ubuntu.
sudo apt install geany
Unduh Clion dari situs web JetBrains resmi:
cd ~/Downloads && wget https://download.jetbrains.com/cpp/CLion-2018.2.5.tar.gz -O clion.tar.gz
sudo tar -xvf clion.tar.gz -C /usr/share
Mari buat tautan untuk membuatnya nyaman untuk menjalankan clion dari konsol.
sudo ln -s /usr/share/clion-2018.2.5/bin/clion.sh /usr/bin/clion
Setelah peluncuran pertama, clion sendiri akan membuat pintasan untuk dirinya sendiri dari menu shell LXpanel, tetapi pertama kali Anda perlu menjalankannya dengan tangan.
Buat ekstensi
Di sini kami memiliki setidaknya 3 opsi:
- Ambil cakram standar mentah dari sumber php yang kami unduh.
- Melihat disk standar sedikit dengan skrip ext_skel khusus
- Dapatkan cakram minimalis yang bagus dari sini .
Saya paling suka opsi ketiga, tetapi saya akan menggunakan yang kedua, jika gagal, untuk meminimalkan jumlah tempat di mana saya bisa salah. Meskipun memilih yang kosong dari pengembang masih menyenangkan :-)
- Mari kita pergi ke direktori dengan ekstensi php standar.
cd /usr/local/src/php-7.2.11/ext
Selain nama skrip, Anda dapat menentukan beberapa parameter ekstensi melalui file proto. Semua ini tidak bisa dilakukan. Saya akan melakukan semuanya dengan tangan, tetapi saya akan menunjukkan cara kerja proto. Kami melakukan trie, jadi beri nama ekstensi kami libtrie. Untuk bekerja di direktori / usr / local / src, Anda memerlukan hak administrator, agar tidak berakhir dengan menulis sudo, saya akan menyertakan bash dengan izin yang lebih tinggi.
sudo bash
- Di sini saya akan menetapkan parameter hanya 1 fungsi yang akan diterapkan oleh ekstensi yang dibuat. Ini hanya fungsi demo untuk menunjukkan bagaimana ini dilakukan.
Kami akan melakukan analog penuh dari fungsi standar
array array_fill ( int $start_index , int $num , mixed $value )
Sintaks dalam file proto sangat sederhana, Anda hanya perlu menentukan nama fungsi. Saya akan menulis sedikit lagi agar terlihat lebih informatif.
echo my_array_fill \( int start_index , int num , mixed value \) >> libtrie.proto
- Sekarang jalankan skrip ext_skel, berikan nama ekstensi dan file proto yang kami buat.
./ext_skel --extname=libtrie --proto=./libtrie.proto
- Kami telah membuat direktori dengan ekstensi kami. Mari kita membahasnya.
cd libtrie
Struktur file dan prinsip perakitan
Struktur file config.m4 - phpize ./configure, makefile. CREDITS - , , libtrie.c - php_libtrie.h - config.w32 - windows EXPERIMENTAL - . , . libtrie.php - php . tests -
Untuk berhasil membangun ekstensi, Anda hanya perlu 3 file. Pada disk ekstensi yang minimalis, yang saya sebutkan di atas, hanya ada 3 file.
config.m4 php_libtrie.h libtrie.c
Saya tidak suka penamaan standar yang diterima di php, saya suka file header dan file dengan badan program diberi nama yang sama. Oleh karena itu ganti nama
libtrie.c
masuk
php_libtrie.c
mv libtrie.c php_libtrie.c
Mengedit config.m4
File config.m4 default benar-benar dijejali dengan konten, yang kelimpahannya membingungkan dan membingungkan. Seperti yang saya katakan, file ini diperlukan untuk membentuk skrip konfigurasi. Baca lebih lanjut tentang ini di
sini .
geany config.m4 &
Kami hanya menyisakan ini:
PHP_ARG_ENABLE(libtrie, whether to enable libtrie support, [ --enable-libtrie Enable libtrie support]) if test "$PHP_LIBTRIE" != "no"; then

Makro pertama menciptakan kemampuan untuk mengaktifkan dan menonaktifkan ekstensi kami saat menjalankan skrip konfigurasi yang dihasilkan.
Blok kedua adalah yang paling penting, menentukan file mana yang akan dikompilasi sebagai bagian dari ekstensi kita, apakah ekstensi akan terhubung secara dinamis melalui file .so, atau apakah ekstensi akan statis dan akan diintegrasikan selama pembuatan php. Kita akan menjadi dinamis.
Simpan file.
Kami menyalin file ke direktori pengguna sehingga tidak berfungsi dalam mode root.
Salin:
cp /usr/local/src/php-7.2.11/ext/libtrie ~/Documents/ -r
Fungsi demo
Biarkan saya mengingatkan Anda bahwa kami akan melakukan analog penuh array_fill (). Saya akan bekerja melalui clion, tetapi panduan ini dapat dilakukan di editor mana pun. Clion baik karena memungkinkan Anda untuk secara otomatis melakukan pemeriksaan sintaksis dasar, dan juga mendukung navigasi cepat melalui file atau fungsi melalui ctrl + klik. Agar transisi seperti itu berfungsi di ekstensi kami, Anda harus mengonfigurasi file CMakeLists.txt
Agar clion dapat berfungsi dengan baik, Anda perlu menginstal sistem build cmake, yang dengannya sekelompok paket dependen diinstal. Instal semua ini dengan perintah:
sudo apt install cmake
Konfigurasikan cmake
Kami membuka katalog kami dengan ekspansi di clion. Buat file CMakeLists.txt dengan konten berikut melalui menu konteks dengan mengklik nama direktori root di bagian atas layar:
cmake_minimum_required(VERSION 3.12) project(php-ext-libtrie C) set(CMAKE_C_STANDARD 11)

Mungkin seseorang tahu bagaimana membuat file ini lebih pendek sehingga clion mulai mengindeks file proyek. Saya tidak menemukan cara yang lebih pendek. Jika ada yang tahu, tulis di komentar.
Kode Fungsi Demo
Buka file kami dengan isi ekstensi
php_libtrie.c
dan
hapus semua komentar sehingga mereka tidak membingungkan kami.


Clion memeriksa untuk melihat apakah semua fungsi dan makro yang digunakan dalam kode telah dideklarasikan dan melemparkan kesalahan jika tidak. Jelas, pengembang PHP tidak menggunakan clion, kalau tidak mereka mungkin akan melakukan sesuatu tentang hal itu. Untuk mencegah kesalahan ini terjadi di ekstensi kami, kami akan menyertakan file header yang hilang kepada kami.
Untuk merampingkan semuanya, saya melakukan ini:
Saya mentransfer semua sertakan dengan tajuk dari file
php_libtrie.h
ke
php_libtrie.h
, hanya 1 entri yang tersisa di file pertama:
#include "php_libtrie.h"

File
php_libtrie.h
akan berisi semua inklusi yang diperlukan lainnya.

Isi file header saya #ifndef PHP_LIBTRIE_H #define PHP_LIBTRIE_H #ifdef HAVE_CONFIG_H #include #endif #include <stdarg.h> // va_start() #include <inttypes.h> // // #if defined(__GNUC__) && __GNUC__ >= 4 # define ZEND_API __attribute__ ((visibility())) # define ZEND_DLEXPORT __attribute__ ((visibility())) #else # define ZEND_API # define ZEND_DLEXPORT #endif # define SIZEOF_SIZE_T 8 // ZVAL_COPY_VALUE() #ifndef ZEND_DEBUG #define ZEND_DEBUG 0 #endif // , #include #include #include #include //ZVAL_COPY_VALUE #include #include #include #include #include extern zend_module_entry libtrie_module_entry; ...
Jika semuanya dilakukan dengan benar, maka clion tester akan menampilkan kotak kuning atau hijau di sudut kanan atas, yang berarti bahwa tidak ada kesalahan kritis.

Penyimpangan teoretis kecil
Agar ekstensi berfungsi dengan baik, 2 hal diperlukan:
- Anda perlu menginisialisasi struktur khusus zend_module_entry, yang berisi yang berikut:
zend_module_entry libtrie_module_entry = { STANDARD_MODULE_HEADER, // "libtrie", // libtrie_functions, // PHP_MINIT(libtrie), //, PHP_MSHUTDOWN(libtrie), // PHP_RINIT(libtrie), /* Replace with NULL if there's nothing to do at request start */ PHP_RSHUTDOWN(libtrie), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(libtrie), // , php phpinfo() PHP_LIBTRIE_VERSION, // , STANDARD_MODULE_PROPERTIES // };
- Inisialisasi array yang sama yang berisi semua fungsi ekstensi kita.
Di sini, melalui pembungkus makro khusus PHP_FE (), nama semua fungsi dalam ekstensi kami ditetapkan. Secara umum, makro sangat aktif digunakan dalam PHP, ada banyak makro yang hanya merujuk ke makro lain, dan pada gilirannya lebih lanjut. Anda harus terbiasa dengannya. Anda dapat mengetahui apakah Anda pergi melalui makro melalui ctrl + klik. Di sini, clion sangat diperlukan.
Ingat file proto? Kami menetapkan 1 fungsi my_array_fill (). Jadi sekarang kita memiliki 3 elemen di sini:
const zend_function_entry libtrie_functions[] = { PHP_FE(confirm_libtrie_compiled, NULL) PHP_FE(my_array_fill, NULL) PHP_FE_END };
Baris pertama adalah fungsi tes yang akan menunjukkan bahwa ekstensi berfungsi, yang kedua adalah fungsi kami, yang ketiga adalah makro khusus, yang harus menjadi yang terakhir dalam array ini.
Temukan fungsi kami:
PHP_FUNCTION(my_array_fill)
Seperti yang Anda lihat, ini juga diinisialisasi melalui makro. Masalahnya adalah bahwa semua fungsi php tidak mengembalikan apa pun (tepatnya, mengembalikan batal) di dalam C, dan argumen mereka tidak dapat diubah. Di suatu tempat bahkan lebih nyaman.
Jika Anda melihat struktur file (bagian dari jendela di sebelah kiri), semua fungsi file tercantum di sini, tetapi dalam bentuk di mana mereka akan setelah mengkompilasi makro. Tangkapan layar menunjukkan bahwa fungsi kami my_array_fill sebenarnya akan menjadi zif_my_array_fill.

Argumen dari usus php ke fungsi C kita kita dapatkan dengan makro. Rincian lebih lanjut tentang makro ini dapat ditemukan di file:
/usr/local/src/php-7.2.11/README.PARAMETER_PARSING_API
Di bawah ini adalah kode fungsi analog kami dengan penjelasan terperinci.
Kode PHP_FUNCTION(my_array_fill) { // , // 2 : // zend_execute_data *execute_data, zval *return_value // , //zend_long int64_t x64 int32_t x86 // zend_long zend_long start_index; //1 , zend_long num; //2 zval *value; // mixed , zval, // , if (zend_parse_parameters(ZEND_NUM_ARGS(), "llz", &start_index, &num, &value) == FAILURE) { /* * RETURN_ * return_value */ RETURN_FALSE; } // , - if (num <= 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "argument 2 must be > 0"); // RETURN_FALSE; } //zval *return_value , // zval, , - // zend_long unsigned int32. // + -. .. 1, 3, 4 array_init_size(return_value, (uint32_t)(start_index + num)); // , , for(zend_long i = start_index, last = start_index + num; i < last; ++i) { // zval add_index_zval(return_value, i, value); } // , return_value return; }
Bangun dan uji ekstensi
Pertama, jalankan phpize, yang akan membuat kita mengonfigurasi file.
phpize
Sekarang jalankan ./configure, yang akan melakukan makefile.
./configure
Akhirnya, jalankan make, yang akan mengumpulkan ekstensi kita.
make
Mari kita periksa apa yang kita lakukan.
Kami masuk di konsol php:
print_r(my_array_fill(50, 2, "hello, baby!"));
Selamat menikmati hasilnya.

Seseorang bertanya, di mana trie di sini? Tentang fungsi yang mengimplementasikan pekerjaan trie, saya akan menulis di bagian kedua.
Tetap disini.