0Pricing
PHP Academy · درس

كتابة إضافة PHP أساسية بلغة C

أنشئ إضافتك الأصلية وحمّلها

كتابة إضافة PHP أساسية بلغة C درس مجاني في PHP Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في PHP Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة PHP Academy 4 دروس في المجموع.

الشيفرة الأصلية في PHP

عندما تكون PHP الخالصة بطيئة جدًا أو تحتاجون إلى ربط مكتبة C، تكتبون امتداد PHP بلغة C باستخدام Zend API. ويعرض الامتداد دوال وفئات أصلية تستدعيها PHP مباشرةً، من دون تكلفة الآلة الافتراضية.

ينشئ هذا الدرس امتداد 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 هذا الملف لإنشاء سكربت configure.

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 واجهة برمجة التطبيقات الأساسية، بينما تُستخدم 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 */

ملفات Arginfo المساعدة

ينشئ 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 كل العناصر معًا: الاسم، والإصدار، وجدول الدوال (من arginfo)، وخطافات دورة الحياة (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 أولًا لإنتاج ترويسة arginfo.

# 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 معلومات arginfo، وتنفّذ PHP_FUNCTION المنطقَ عبر تحليل الوسائط باستخدام ZEND_PARSE_PARAMETERS وإعادة القيمة باستخدام RETURN_STR، بينما يربط zend_module_entry خطافات دورة الحياة. ابنِ الإضافة باستخدام phpize ← configure ← make، ثم حمّل الملف .so واختبره من PHP. استخدم emalloc لذاكرة الطلب، وفكّر في FFI قبل الالتزام بكتابة تعليمات أصلية.

الأسئلة الشائعة

هل درس «كتابة إضافة PHP أساسية بلغة C» مجاني؟

نعم — نص درس «كتابة إضافة PHP أساسية بلغة C» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة PHP Academy، انتقل إلى CoddyKit PRO. تتضمن دورة PHP Academy 4 دروس في المجموع.

ماذا ستتعلم في «كتابة إضافة PHP أساسية بلغة C»؟

أنشئ إضافتك الأصلية وحمّلها تتمرن على PHP Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ PHP Academy؟

لا تُشترط خبرة سابقة. PHP Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «كتابة إضافة PHP أساسية بلغة C»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس PHP Academy هذا؟

نعم. كل درس في PHP Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. كيف تعمل Zend Engine
  2. إدارة الذاكرة وجمع البيانات المهملة
  3. ترجمة OPcache وJIT
  4. كتابة إضافة PHP أساسية بلغة C
← العودة إلى PHP Academy