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 installedconfig.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)
fiNagłó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)
#endifPamięć: 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
- Jak działa Zend Engine
- Zarządzanie pamięcią i garbage collection
- OPcache i kompilacja JIT
- Pisanie podstawowego rozszerzenia PHP w C