Piszemy własne rozszerzenie php (php extension) – część 1

Tym wpisem chciałbym zapoczątkować cykl artykułów na temat tworzenia własnych rozszerzeń PHP (php extension). Wiedza konieczna do ogarnięcia informacji zawartych w tym artykule (i mam nadzieję następnych) to znajomość języka C (tak, właśnie w C jest napisane silnik php) oraz podstawowa znajomość języka PHP.

Zaczynamy

Na początku chciałbym przedstawić trochę teorii na temat tego czym są, a czym nie są rozszerzenia php, po co nam one w ogóle są potrzebne, oraz jak funkcjonuje samo php i jego rozszerzenia.
Na początku usystematyzujmy trochę naszą wiedzą. Czym jest rozszerzenie PHP ? Otóż rozszerzenie udostępnia nam w postaci API jakąś bibliotekę programistyczną lub jakieś inne zasoby. np. rozszerzenie mysql_* udostępnia nam w postaci API funkcje z bibliotek MySQL. W taki sam sposób możemy udostępnić praktycznie każdą inną bibliotekę. Poniżej zostało to zobrazowane w postaci prostego diagramu.

Budowa rozszerzenia php

Zanim rozpoczniemy pracę nad naszym pierwszym rozszerzeniem, musimy lepiej poznać samą strukturę (budowę wewnętrzną) PHP. Składa się ono z 5 niezależnych elementów, tak jak pokazuje to poniższy rysunek:

Na samym dole mamy SAPI (API serwera www), które jest odpowiedzialne za cykl życia php, oraz stanowi pomost pomiędzy serwerem www (np. mod_php5.so dla apachea), a php, lub linią poleceń a php gdy korzystamy z CLI.

Powyżej SAPI mamy Core PHP, który jest odpowiedzialny za obsługę niektórych niskopoziomowych operacji takich jak np. obsługa błędów czy dostęp do plików lub obsługa błędów, oraz dostarcza bindingi do kluczowych eventów (wywołań).

Obok Core mamy Zenda który jest odpowiedzialny za parsowanie skryptu, zamiane go w bytecode a następnie uruchomienie go w maszynie wirtualnej, gdzie czyta i modyfikuje zmienne z przestrzeni użytkownika, steruje przepływem programu itd. Oprócz tego Zend zajmuje się obsługą pamięci zajmowanej tylko na czas requestu oraz dostarcza API do manipulowania środowiskiem.

I na samej górze mamy nasze rozszerzenia, które są niczym innym jak ładowanymi fragmentami kodu. Niektóre z nich mogą być wkompilowane na stałe, inne mogą być dynamicznie dołączane i odłączane poprzez plik konfiguracyjny php.ini i dyrektywę extension= lub z przestrzeni użytkownika za pomocą funkcji dl().

Wszystko to razem jest określone jako warstwa TSRM (Thread Safe Resource Management).

Minimum na temat rozszerzeń

OK, a więc wiemy jak mniej/więcej wygląda budowa php. Skupmy się zatem nad tym czym jest samo rozszerzenie.

Mówiąc najprościej rozszerzenie to mała paczka kodu która może być włączona w php, dodając do niego nowe elementy API w przestrzeni skryptu/użytkownika.

Każda taka paczka (rozszerzenie) musi współdzielić jedną strukturę danych – zend_module_entry która znajduje się w pliku Zend/zend_modules.h. Struktura zend_module_entry, to pewnego rodzaju punkt rozpoczęcia, gdzie php informuje nasz moduł o sobie (swojej wersji i innych parametrach) oraz odczytuje informację na temat metod które mają zostać uruchomione na starcie i na zakończeniu (startup i shutdown), metody te są wykorzystywane podczas „cyklu życia” który postaram się opisać w następnej części artykułu którą chciałbym w całości im mu poświęcić.

Oprócz powyższego struktura zend_entry_module zawiera tablicę struktur zend_function_entry która została zdefiniowana w pliku Zend/zend_API.h, a która jak można się domyśleć zawiera funkcję które mają zostać zarejestrowane jako nowe elementy API i być dostępne w skrypcie.

W następnej części postaram się opisać jak wygląda lifecycle oraz czym różnią się one względem siebie w modelach CLI, wielo-procesowym, wielo-wątkowym, oraz wbudowanym.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *