Mirin webspace

Nejbohatší život má ten, kdo žije s minimem nároků

30. 6. 2010 PHP

PHP extension - základ modulu

Z minula máme základní konfiguraci modulu pro PHP rozšíření, dnes tedy něco k tomu, jak v C vypadá taková kostra PHP modulu. Modul, jak jsme si řekli minule je v podstatě to samé co PHP extente. Není zvykem, že by jedna extenze obsahovala více modulů. Psaní kostry modulu je v podstatě rutina a proto vzniklo několik automatizovaných řešení. V PHP 4 se jednalo o shell skript ext_skel, pak vznikl Pecl_Gen, jediný PHP kód v Pecl repozitáři, který se posléze vrátil zpět do PEARu jako CodeGen_PECL. Takže buď použijte ten, nebo si to napište sami :-). Budu opět vycházet ze své incpath extenze.

Vždy je lepší se držet minimálního množství kódu v hlavičkách, tak i proto se ve hlavičkovém souboru nebudeme příliš rozepisovat, necháme jen základ a využijeme direktivy extern a vlastní definici struktrury modulu necháme ve zdrojovém kódu modulu (extname.c).

#ifndef PHP_EXTNAME_H
#define PHP_EXTNAME_H
 
extern zend_module_entry extname_module_entry;
#define phpext_extname_ptr &extname_module_entry
 
#ifdef ZTS
#include "TSRM.h"
#endif
 
#endif	/* PHP_EXTNAME_H  */

Tady opravdu není nic moc co dodávat, define pro zabránění opakované definici každý zná a Zend Enginu opravu stačí pouze externalizovaná definice modulu. O thread safe - TSRM někdy příště.

Modul samotný (extname.c) musí obsahovat už tuto strukturu definovanou. Tahle struktura je vlastně definice všeho, co naše extenze obsahuje a z ní Zend Engine načerpá informace o funkcích, třídách, konstantách a všem ostatním, co náš modul obsahuje. Základní věcí jsou funkce MINIT, MINFO a spol. To jsou takové styčné body naší extenze do core PHP a jsou volány v různých etapách přímo jádrem PHP. Názvy jsou samo vypovídající. M-funkce jsou volány při inicializaci a uvolnění modulu, typicky při restartu Apache a natažení PHP modulu a R-funkce při zahájení a konci nového požadavku (např HTTP). Málokterá extenze R-funkcí využívá, ale je dobré vědět o tom, že extension API má bod pro pověšení se na začátek a konec HTTP požadavku.

Trochu výjimka je MINFO, které slouží k výpisu informací o modulu ve výpisu generovaném funkcí phpinfo().

#include "php.h"
#include "php_extname.h"
 
#ifdef COMPILE_DL_EXTNAME
    ZEND_GET_MODULE(EXTNAME)
#endif
 
static PHP_MINIT_FUNCTION(extname)
{
	/* registrace konstant, tříd, .. */
	return SUCCESS;
}
 
static PHP_MINFO_FUNCTION(extname)
{
	php_info_print_table_start();
	php_info_print_table_row(2, "Extname support", "enabled");
	php_info_print_table_end();
}
 
static PHP_FUNCTION(extname_function)
{
 
}
 
static zend_function_entry extname_functions[] = {
	PHP_FE(extname_function, arginfo_my_function)
	{NULL, NULL, NULL}
};
 
zend_module_entry extname_module_entry = {
    STANDARD_MODULE_HEADER,
    "extname",
    extname_functions,
    PHP_MINIT(extname),
    NULL, //PHP_MSHUTDOWN(extname),
    NULL, //PHP_RINIT(extname)
    NULL, //PHP_RSHUTDOWN(extname)
    PHP_MINFO(extname),
    "0.1",
    STANDARD_MODULE_PROPERTIES
};

Součástí definice modulu je i struktra se seznamem našich funkcí - zend_function_entry. PHP si je zaregistruje a pak už nic nebrání tomu volat funkce našeho modulu z userspace PHP skriptu.

Při statické definici funkcí a struktur je dobré mít definici modulu nakonci, myslím, že i tak velí konvence Cčkového kompilátoru, ale už přesně nevím.

Jinak tady je pěkně vidět, jak silně jsou při psaní modulů využívány makra Cčkového preprocesoru. Je to poprvé, kdy jsem se setkal v Cčku s makrem pro funkce. To je jedna z velkých zbraní Cčka, přetavená v C++ do ultra silného nástroje - šablon. Třeba takové PHP_FUNCTION je makro, které se před kompilací přemění v Cčkový kód všude, kde je potřeba a takových maker je v API spousty a velmi často se s nimi setkáte, stačí si projít hlavičkové soubory adresáři Zend ve zdrojových kódech PHP.

Je dobré zdůraznit, že chyby v MINIT/RINIT_FUNCTION se dost špatně hledají a ladí (pokud tedy asi nepoužíváte gdb). Většinou se prostě modul nenatáhne a vy dostanete jen strohou hlášku do logu.

No a teď už v podstatě stačí zimplementovat všechny naše PHP_FUNCTION a je hotovo. Ještě jsem zapoměl na arginfo V PHP_FE položce zend_function_entry, to slouží hlavně pro účely reflexe, o tom a něčem dalším z tvorby php rozšíření zase někdy příště.


Komentáře (0)

Komentáře jsou uzavřeny.