การเขียนส่วนขยาย PHP พื้นฐานด้วย C
สร้างและโหลดส่วนขยายเนทีฟของคุณเอง
การเขียนส่วนขยาย PHP พื้นฐานด้วย C เป็นบทเรียน PHP Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PHP Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
โค้ดเนทีฟใน PHP
เมื่อ PHP ล้วนทำงานช้าเกินไป หรือคุณต้องเชื่อมต่อกับไลบรารี C คุณสามารถเขียนส่วนขยาย PHPด้วยภาษา C โดยใช้ Zend API ส่วนขยายจะเปิดให้ PHP เรียกใช้ฟังก์ชันและคลาสเนทีฟได้โดยตรง โดยไม่ต้องผ่านต้นทุนของ VM
บทเรียนนี้จะสร้างส่วนขยาย hello แบบเรียบง่ายตั้งแต่ต้นจนจบ ได้แก่ โครงร่าง ฟังก์ชัน การสร้าง การโหลด และการทดสอบ
ชุดเครื่องมือสร้าง
ส่วนขยายสร้างด้วย phpize ของ PHP ซึ่งเตรียมการสร้างด้วย autoconf โดยใช้ส่วนหัวของ PHP ที่ติดตั้งอยู่ คุณต้องมี php-dev/php-devel (มี phpize และ php-config ให้ใช้) รวมทั้งคอมไพเลอร์ภาษา C และ make.
# Install build prerequisites (Debian/Ubuntu)
sudo apt install php-dev build-essential
# Confirm the tools exist
phpize --version
php-config --extension-dir # where the .so will be installedconfig.m4
ส่วนขยายทุกส่วนต้องมี config.m4 สำหรับลงทะเบียนแฟล็กการสร้างและประกาศไฟล์ต้นฉบับ phpize จะใช้ไฟล์นี้สร้างสคริปต์กำหนดค่า
dnl config.m4 for the 'hello' extension
PHP_ARG_ENABLE([hello],
[whether to enable hello support],
[AS_HELP_STRING([--enable-hello], [Enable hello])],
[no])
if test "$PHP_HELLO" != "no"; then
PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)
fiส่วนหัวของส่วนขยาย
ซอร์สโค้ด C นำเข้าส่วนหัวของ Zend/PHP และประกาศจุดเริ่มต้นของโมดูล php.h ดึง API หลักเข้ามา ส่วน ext/standard/info.h ใช้สำหรับผลลัพธ์จาก phpinfo() ส่วนขยายทุกส่วนจะกำหนด zend_module_entry
/* hello.c — includes */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "ext/standard/info.h"
#include "hello_arginfo.h" /* generated from stub */สตับข้อมูลอาร์กิวเมนต์
PHP สมัยใหม่สร้างข้อมูลเมทาดาทาของอาร์กิวเมนต์จากไฟล์ .stub.php คุณเขียนลายเซ็นฟังก์ชันด้วยไวยากรณ์คล้าย PHP แล้ว gen_stub.php จะสร้าง hello_arginfo.h วิธีนี้ช่วยให้ข้อมูลการสะท้อนและข้อมูลชนิดถูกต้อง
<?php
// hello.stub.php — describes the native function's signature
/** @generate-class-entries */
function hello_greet(string $name): string {}
?>การเขียนฟังก์ชัน
ฟังก์ชันเนทีฟคือฟังก์ชัน C ที่กำกับด้วย PHP_FUNCTION คุณแยกวิเคราะห์อาร์กิวเมนต์ขาเข้าด้วยมาโคร ZEND_PARSE_PARAMETERS และคืนค่าผ่านมาโคร RETURN_* ในที่นี้เราจะสร้างสตริงคำทักทาย
/* hello.c — the native function */
PHP_FUNCTION(hello_greet)
{
char *name;
size_t name_len;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STRING(name, name_len)
ZEND_PARSE_PARAMETERS_END();
/* Build "Hello, <name>!" into a new zend_string */
zend_string *result = strpprintf(0, "Hello, %s!", name);
RETURN_STR(result); /* hands ownership to the engine */
}จุดเริ่มต้นของโมดูล
zend_module_entry เชื่อมทุกอย่างเข้าด้วยกัน ได้แก่ ชื่อ รุ่น ตารางฟังก์ชัน (จากข้อมูลอาร์กิวเมนต์) และจุดเชื่อมต่อวงจรชีวิต (MINIT, RINIT, MINFO) ส่วน ZEND_GET_MODULE จะส่งออกสัญลักษณ์จุดเริ่มต้นที่ตัวโหลดใช้ค้นหา
/* hello.c — module wiring */
zend_module_entry hello_module_entry = {
STANDARD_MODULE_HEADER,
"hello", /* extension name */
ext_functions, /* function table from arginfo */
NULL, /* MINIT (module startup) */
NULL, /* MSHUTDOWN */
NULL, /* RINIT (per-request) */
NULL, /* RSHUTDOWN */
PHP_MINFO(hello), /* phpinfo section */
"0.1.0",
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_HELLO
ZEND_GET_MODULE(hello)
#endifหน่วยความจำ: emalloc เทียบกับ malloc
ภายในส่วนขยาย ให้จัดสรรหน่วยความจำที่มีอายุการใช้งานตลอดคำขอด้วย emalloc/efree (จัดการโดยตัวจัดการหน่วยความจำ Zend และปล่อยเมื่อคำขอสิ้นสุด) — อย่าใช้ malloc โดยตรง สำหรับการจัดสรรแบบถาวร (ใช้ข้ามคำขอ) ให้ใช้ pemalloc การคืนค่า zend_string ผ่าน RETURN_STR จะโอนความเป็นเจ้าของให้เอนจิน ซึ่งจะเป็นผู้ปล่อยหน่วยความจำนั้น
/* Request-scoped buffer the engine will clean up on error/shutdown */
char *buf = emalloc(64);
/* ... use buf ... */
efree(buf);
/* Persistent allocation surviving the request (rare) */
/* char *cfg = pemalloc(128, 1); ... pefree(cfg, 1); */การสร้าง
การสร้างแบบสามขั้นตอนคลาสสิก ได้แก่ ใช้ phpize เพื่อเตรียมโครงสร้าง ใช้ ./configure พร้อมแฟล็กเปิดใช้ของคุณ แล้วจึงใช้ make อย่าลืมเรียก gen_stub.php ก่อนเพื่อสร้างส่วนหัวข้อมูลอาร์กิวเมนต์
# Generate arginfo from the stub
php /path/to/php-src/build/gen_stub.php hello.stub.php
# Scaffold + configure + compile
phpize
./configure --enable-hello
make
# Result lands in modules/hello.so
ls -la modules/hello.soการโหลดและการทดสอบ
โหลดไฟล์ .so ที่คอมไพล์แล้วด้วย -d extension=... (หรือเพิ่มลงในไฟล์ ini) จากนั้นเรียกฟังก์ชันเนทีฟจาก PHP ได้เหมือนฟังก์ชันในตัวทุกประการ นี่คือลักษณะของสคริปต์ทดสอบ/ตรวจสอบของคุณหลังจากติดตั้งส่วนขยายแล้ว
<?php
// After: php -d extension=./modules/hello.so test.php
if (!extension_loaded('hello')) {
fwrite(STDERR, "hello extension not loaded\n");
exit(1);
}
echo hello_greet('Zend') . PHP_EOL; // Hello, Zend!
var_dump(extension_loaded('hello')); // bool(true)
?>เมื่อใด (ไม่) ควรเขียนส่วนขยาย
ส่วนขยายเนทีฟมีต้นทุนในการบำรุงรักษา ทั้งข้อบกพร่องด้านหน่วยความจำใน C การต้องสร้างใหม่สำหรับ PHP แต่ละรุ่นย่อย และความเข้ากันไม่ได้ของ ABI ก่อนเลือกใช้โค้ดเนทีฟ โปรดพิจารณา FFI (เรียกใช้ไลบรารี C จาก PHP โดยไม่ต้องคอมไพล์ส่วนขยาย) หรือการปรับประสิทธิภาพด้วย PHP ล้วน เลือกใช้ส่วนขยาย C เมื่อคุณต้องการความเร็วสูงสุด การผสานรวมกับเอนจินในระดับลึก หรือการห่อหุ้มไลบรารี C ที่ซับซ้อนอย่างเป็นระเบียบ
<?php
// FFI alternative: call a C library directly, no extension build
$ffi = FFI::cdef(
"int abs(int);", // declare the symbol
"libc.so.6"
);
echo $ffi->abs(-42) . PHP_EOL; // 42
?>ตรวจสอบความเข้าใจ
ภายในส่วนขยาย ควรใช้ตัวจัดสรรหน่วยความจำใดเพื่อเก็บหน่วยความจำที่มีอายุการใช้งานตลอดคำขอ
สรุปทบทวน
คุณได้สร้างส่วนขยาย C ขนาดเล็ก โดย config.m4 ลงทะเบียนการสร้าง ไฟล์ .stub.php สร้างข้อมูลอาร์กิวเมนต์ PHP_FUNCTION ใช้สร้างตรรกะด้วยการแยกวิเคราะห์อาร์กิวเมนต์ผ่าน ZEND_PARSE_PARAMETERS และคืนค่าผ่าน RETURN_STR ส่วน zend_module_entry เชื่อมจุดเชื่อมต่อวงจรชีวิตเข้าด้วยกัน สร้างด้วย phpize → configure → make โหลดไฟล์ .so แล้วทดสอบจาก PHP ใช้ emalloc สำหรับหน่วยความจำของคำขอ และพิจารณา FFI ก่อนตัดสินใจใช้โค้ดเนทีฟ
คำถามที่พบบ่อย
บทเรียน “การเขียนส่วนขยาย PHP พื้นฐานด้วย C” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การเขียนส่วนขยาย PHP พื้นฐานด้วย C” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PHP Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเขียนส่วนขยาย PHP พื้นฐานด้วย C”
สร้างและโหลดส่วนขยายเนทีฟของคุณเอง คุณปฏิบัติ PHP Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PHP Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน PHP Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การเขียนส่วนขยาย PHP พื้นฐานด้วย C” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน PHP Academy นี้ได้ไหม
ได้ บทเรียน PHP Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การทำงานของ Zend Engine
- การจัดการหน่วยความจำและการเก็บขยะ
- OPcache และการคอมไพล์ JIT
- การเขียนส่วนขยาย PHP พื้นฐานด้วย C