0Pricing
PHP Academy · บทเรียน

การเขียนส่วนขยาย 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 installed

config.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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การทำงานของ Zend Engine
  2. การจัดการหน่วยความจำและการเก็บขยะ
  3. OPcache และการคอมไพล์ JIT
  4. การเขียนส่วนขยาย PHP พื้นฐานด้วย C
← กลับไปที่ PHP Academy