
Ringkasan bagian pertama :
- Instalasi dan konfigurasi alat.
- Menulis fungsi
helloWorld()
di Kotlin Native dan mengkompilasinya ke perpustakaan bersama. - Akses fungsi ini dari kode ekstensi PHP C.
Pada artikel ini, saya akan berbicara tentang membuat alat untuk menulis ekstensi PHP tanpa harus menyentuh C, secara eksklusif pada K / N.
Siapa yang peduli - selamat datang di kucing.
Siapa pun yang membaca tidak tertarik, tetapi hanya ingin melihatnya - selamat datang di
githubPada awalnya saya ingin mengucapkan terima kasih banyak kepada Nikolai Igotti untuk jawaban cepat dan berkualitas tinggi untuk pertanyaan saya, kadang-kadang konyol dan naif, di saluran kendur Asli Kotlin.Segera buat reservasi yang saya tidak pura-pura membuat kerangka kerja lengkap (mungkin nanti), oleh karena itu kami akan membatasi fungsionalitas dengan cara ini:
- Membuat fungsi yang bisa dipanggil dari kode PHP.
- Definisi konstanta.
- Kami hanya beroperasi dengan tipe PHP sederhana:
string
, boolean
, int
, float
(dan null
). Tidak ada array, objek, sumber daya, transfer dengan referensi, dll. - Saya akan memberi tahu Anda alasannya di bawah ini.
Kekhasan pengembangan ekstensi PHP adalah bahwa hampir semua kode utilitas dan komunikasi dengan
zend engine
ditulis pada makro. Di satu sisi, ini sangat memudahkan penulisan ekstensi dalam C, dan di sisi lain, itu membuatnya sangat sulit untuk melakukan hal yang sama dalam semua bahasa pemrograman lainnya.
Dengan perkenalan seperti itu, solusi yang paling jelas adalah menggunakan coderinarium. Dan, mengingat Kotlin memberikan kemungkinan yang sangat luas untuk membuat DSL, proses menggambarkan struktur ekstensi dapat dibuat sederhana dan intuitif.
Untuk membangun perpustakaan ekstensi dengan cara klasik (phpize, configure, make), setidaknya diperlukan dua artefak - kode ekstensi dalam C dan file
config.m4
.
Skenario penggunaan akan seperti ini:
- Menggunakan DSL, kami menjelaskan ekstensi.
- Kami menulis implementasi fungsi pada K / N.
- Menurut deskripsi, kami menghasilkan
extension.c
dan config.m4
. Kode dalam extencion.c
akan berurusan dengan extencion.c
dangkal panggilan fungsi. - Menurut deskripsi, kami menghasilkan
constants.kt
, yang memungkinkan kami untuk menggunakan konstanta yang diberikan dalam fungsi kami di K / N. - Kami mengkompilasi kode K / N ke perpustakaan statis.
- Menyatukan semuanya dan mengompilasinya ke pustaka ekstensi.
Ayo pergi!
Untuk mengimplementasikan rencana kami, kami perlu mendapatkan sesuatu seperti struktur ini:
(, ) 1 2 ... 1(, ) 1 2 ... 1 ...
Saya pikir tidak akan sulit bagi siapa pun yang bekerja dengan Kotlin untuk menulis DSL yang sesuai. Selebihnya, ada sejumlah besar artikel khusus di mana topik ini dibahas lebih detail daripada jika saya mencoba melakukan ini sebagai bagian dari artikel ini.
Langkah selanjutnya adalah mengubah DSL ini menjadi artefak yang diperlukan. Untuk melakukan ini, kita akan menulis generator pada K / N yang sama, mengkompilasi file yang dapat dieksekusi dari itu dan DSL kita dan menjalankannya - voila! Solusinya bukan yang paling elegan, tetapi belum ada yang lebih sederhana dan dapat diandalkan terjadi pada saya.
Nah, semuanya sederhana - kami mengkompilasi perpustakaan dengan fungsi dan mengumpulkan ekstensi secara teratur, termasuk di sana.
Untuk kemudahan penggunaan, semua sihir dengan kompilasi disembunyikan dalam skrip shell.Apa yang terjadi?
Contoh deskripsi dan kode yang dihasilkan untuk ekstensi sederhana yang dijelaskan pada DSL ini (
untuk pemahaman yang lebih baik, semua argumen diberikan dalam bentuk bernama ).
konfigure.kt - ekstensi DSL import php.extension.dsl.* val dsl = extension(name = "example", version = "0.1") { constant(name = "HELLO_EN", value = "Hello") constant(name = "HELLO_ES", value = "Hola") constant(name = "HELLO_RU", value = "") function(name = "hello", returnType = ArgumentType.STRING) { arg(type = ArgumentType.STRING, name = "name") arg(type = ArgumentType.STRING, name = "lang", optional = true) } } fun main(args: Array<String>) = dsl.make()
example.kt - Fungsi pelaksana fun hello(name: String, lang: String?) = "${if (lang ?: "" == "") HELLO_EN else lang} $name!!!\n"
Perhatikan algoritma aneh untuk menentukan nilai untuk `lang`. Ini disebabkan oleh bug dalam versi K / N saat ini, yang tidak memungkinkan untuk meneruskan variabel tipe `char *` yang tidak diinisialisasi sebagai argumen dari C. - Anda harus melewatkan string kosong.
config.m4 - file yang dihasilkan PHP_ARG_ENABLE(example, whether to enable example support,[ --enable-example Enable hello support]) if test "$PHP_EXAMPLE" != "no"; then PHP_ADD_INCLUDE(.) PHP_ADD_LIBRARY_WITH_PATH(example_kt, ., EXAMPLE_SHARED_LIBADD) PHP_SUBST(EXAMPLE_SHARED_LIBADD) PHP_NEW_EXTENSION(example, example.c, $ext_shared) fi
example_generated_constants.kt - file yang dihasilkan dengan konstanta Kotlin const val HELLO_EN = "Hello" const val HELLO_ES = "Hola" const val HELLO_RU = ""
example.c - file yang dihasilkan dengan kode C. #include "php.h" #include "example_kt_api.h" PHP_FUNCTION(hello); static zend_function_entry example_functions[] = { PHP_FE(hello, NULL) {NULL,NULL,NULL} }; PHP_MINIT_FUNCTION(example); zend_module_entry example_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif "example", example_functions, PHP_MINIT(example), NULL, NULL, NULL, NULL, #if ZEND_MODULE_API_NO >= 20010901 "0.1", #endif STANDARD_MODULE_PROPERTIES }; ZEND_GET_MODULE(example) PHP_MINIT_FUNCTION(example) { REGISTER_STRING_CONSTANT("HELLO_EN", "Hello", CONST_CS|CONST_PERSISTENT); REGISTER_STRING_CONSTANT("HELLO_ES", "Hola", CONST_CS|CONST_PERSISTENT); REGISTER_STRING_CONSTANT("HELLO_RU", "", CONST_CS|CONST_PERSISTENT); return SUCCESS; } PHP_FUNCTION(hello){
Tentang mengapa hanya tipe sederhana
Karena mereka adalah pemetaan 1-1 untuk jenis asli Kotlin. Sampai saat ini, proyek mengimplementasikan, pada kenyataannya, interop hanya dalam satu arah, yaitu memanggil fungsi K / N dari C. Untuk memproses tipe kompleks, seperti
zend_value
,
zend_class_entry
atau
zend_fcall_info
, Anda perlu mengimpor struktur terkait ke proyek K / N dan menulis pembungkus yang sesuai untuk bekerja dengannya, dan ada juga semua makro, dll.
Toples dengan tar. Sendok terpasang.
- Dokumentasi Asli Kotlin. Tampaknya ada di sana, tapi ... Sejauh ini, cara belajar yang paling dapat diandalkan adalah membaca sumbernya.
- Ukuran ekstensi yang dihasilkan tidak terlalu kecil. Untuk contoh di atas, perpustakaan sekitar 500KB diperoleh.
- Anda bahkan tidak perlu berharap bahwa ekstensi yang ditulis dalam K / N akan berakhir di perpustakaan ekstensi PHP. Produk ini diperoleh, sehingga untuk berbicara, hanya untuk penggunaan internal.
Apa selanjutnya
Terapkan semua yang dijelaskan di bagian "Tentang mengapa hanya tipe sederhana".
Sekali lagi,
tautan ke repositori .
Terima kasih atas perhatiannya, doakan semoga sukses :)