0Pricing
PHP Academy · Lekcja

Pisanie podstawowego rozszerzenia PHP w C

Zbuduj i załaduj własne natywne rozszerzenie

Pisanie podstawowego rozszerzenia PHP w C to bezpłatna lekcja PHP Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej PHP Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs PHP Academy zawiera 4 lekcji w sumie.

Kod natywny w PHP

Gdy czysty PHP jest zbyt wolny lub potrzebne jest powiązanie biblioteki C, należy napisać rozszerzenie PHP w języku C, korzystając z Zend API. Rozszerzenie udostępnia natywne funkcje i klasy, które PHP wywołuje bezpośrednio, bez narzutu maszyny wirtualnej.

W tej lekcji od początku do końca zbudowano minimalne rozszerzenie hello: szkielet, funkcję, kompilację, ładowanie i test.

Łańcuch narzędzi do budowania

Rozszerzenia buduje się za pomocą phpize z PHP, które przygotowuje proces budowania oparty na autoconf, korzystając z nagłówków zainstalowanego PHP. Potrzebne są pakiety php-dev/php-devel (udostępniające phpize i php-config), a także kompilator C i 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

Każde rozszerzenie wymaga pliku config.m4, który rejestruje flagę budowania i deklaruje pliki źródłowe. phpize korzysta z niego, aby wygenerować skrypt 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

Nagłówki rozszerzenia

Kod źródłowy w C dołącza nagłówki Zend/PHP i deklaruje wpis modułu. php.h dołącza główny interfejs API, a ext/standard/info.h służy do generowania danych wyjściowych funkcji phpinfo(). Każde rozszerzenie definiuje element 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 */

Stuby arginfo

Współczesne wersje PHP generują metadane argumentów na podstawie pliku .stub.php. Sygnaturę funkcji zapisuje się w składni podobnej do PHP, a gen_stub.php tworzy plik hello_arginfo.h. Dzięki temu informacje dostępne przez refleksję oraz informacje o typach pozostają dokładne.

<?php
// hello.stub.php — describes the native function's signature
/** @generate-class-entries */

function hello_greet(string $name): string {}
?>

Implementowanie funkcji

Funkcja natywna to funkcja w C oznaczona za pomocą PHP_FUNCTION. Argumenty wejściowe analizuje się za pomocą makr ZEND_PARSE_PARAMETERS, a wartości zwraca za pomocą makr RETURN_*. W tym przykładzie tworzymy tekst powitania.

/* 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 */
}

Wpis modułu

Element zend_module_entry łączy wszystkie elementy: nazwę, wersję, tablicę funkcji (pochodzącą z arginfo) oraz funkcje cyklu życia (MINIT, RINIT, MINFO). ZEND_GET_MODULE eksportuje symbol wpisu, którego szuka moduł ładujący.

/* 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

Pamięć: emalloc a malloc

W rozszerzeniu pamięć na czas żądania należy przydzielać za pomocą emalloc/efree (jest śledzona przez menedżer pamięci Zend i zwalniana po zakończeniu żądania) — nie za pomocą surowego malloc. Do trwałych alokacji (współdzielonych między żądaniami) należy używać pemalloc. Zwrócenie elementu zend_string za pomocą RETURN_STR przekazuje własność silnikowi, który go zwolni.

/* 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); */

Budowanie rozszerzenia

Klasyczny proces budowania składa się z trzech kroków: phpize tworzy szkielet, ./configure uruchamia się z flagą włączającą rozszerzenie, a następnie wykonuje się make. Należy pamiętać, aby najpierw uruchomić gen_stub.php i utworzyć nagłówek 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

Ładowanie i testowanie

Skompilowany plik .so ładuje się za pomocą -d extension=... (lub dodaje do pliku ini). Następnie można wywoływać funkcję natywną z PHP dokładnie tak jak funkcję wbudowaną. Tak wygląda skrypt testujący i weryfikujący działanie po zainstalowaniu rozszerzenia.

<?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)
?>

Kiedy (nie) warto je pisać

Rozszerzenia natywne wiążą się z kosztami utrzymania: błędami pamięci w C, koniecznością ponownej kompilacji dla każdej podrzędnej wersji PHP oraz niezgodnością ABI. Przed napisaniem kodu natywnego warto rozważyć FFI (wywoływanie bibliotek C z PHP bez kompilowania rozszerzenia) lub optymalizację kodu w czystym PHP. Po rozszerzenie C warto sięgać, gdy potrzebna jest maksymalna szybkość, głęboka integracja z silnikiem lub czyste opakowanie złożonej biblioteki 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
?>

Szybkie sprawdzenie

Jaki alokator powinien przechowywać pamięć na czas żądania w rozszerzeniu?

Podsumowanie

Utworzyli Państwo minimalne rozszerzenie w C: config.m4 rejestruje proces budowania, plik .stub.php generuje arginfo, PHP_FUNCTION implementuje logikę, analizując argumenty za pomocą ZEND_PARSE_PARAMETERS i zwracając wynik przez RETURN_STR, a element zend_module_entry łączy funkcje cyklu życia. Rozszerzenie buduje się za pomocą phpize → configure → make, następnie ładuje plik .so i testuje działanie z poziomu PHP. Do pamięci na czas żądania należy używać emalloc — a przed zdecydowaniem się na kod natywny warto rozważyć FFI.

Często zadawane pytania

Czy lekcja „Pisanie podstawowego rozszerzenia PHP w C” jest bezpłatna?

Tak — pełny tekst „Pisanie podstawowego rozszerzenia PHP w C” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu PHP Academy, przejdź na CoddyKit PRO. Kurs PHP Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Pisanie podstawowego rozszerzenia PHP w C”?

Zbuduj i załaduj własne natywne rozszerzenie Ćwiczysz PHP Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć PHP Academy?

Nie wymagamy żadnego doświadczenia. PHP Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Pisanie podstawowego rozszerzenia PHP w C”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji PHP Academy?

Tak. Każda lekcja PHP Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Jak działa Zend Engine
  2. Zarządzanie pamięcią i garbage collection
  3. OPcache i kompilacja JIT
  4. Pisanie podstawowego rozszerzenia PHP w C
← Powrót do PHP Academy