Реализация классов в PHP5 экстеншене, пример, надеюсь с подробным объяснением
Реализация классов в PHP5 экстеншене:
Я не претендую на полноту изложения, возможно предложенные подходы и отличаются от принятых подходов разработчиков PHP, но вакуум который создался в отношении реализации классов в экстеншенах, мне бы хотелось хоть как-то заполнить. Каждый может заполнить по своему и надеюсь, пост натолкнёт Вас на более продвинутые мысли и свои способы реализации.
В основном это рассчитано, на тех кто уже знаком с написанием экстеншенов. Если конечно пост удасться, и будет в этом желание, то могу наверно написать, еще так сказать и азы.
PS: Я отлаживаю экстеншены под Windows используя Visual Studio, ничего не имею против Linux-а, просто мне удобней. Весь код является кросплатформенным и компилируется как под Windwos, так и под Linux, как с консоли, так и с помощью KDevelop и VS, но настройку проектов под KDev и VS я опущу (это отдельная история).
Рассматривать буду на живом примере, в смысле который потом можно скомпилировать, так сказать пошагово. Внимание заострено, на классах, поэтому многие вещи, такие как настройки php.ini, глобальные переменные модуля и т.д., опущены.
1. Структура проекта
php_foo.h
php_foo.c
config.m4
config.w32
2. config.m4 - определяет параметры, файлы экстеншена, для компиляции
3. config.w32 - этот файл конфигурации нужен для компиляции экстеншена под Windows
4. php_foo.h - заголовочный файл проекта
5. php_foo.c - непосредственно реализация тела модуля и класса
Объявляем несколько глобальных переменных, в первой из них g_ClassEntry, будет находиться адрес класса зарегистрированного в глобальной таблице классов php, на случай, если нам понадобиться обратиться к нему. Во вторую переменную, после регистрации, скопируем адреса стандартных функций обработчиков (__get,__set,__clone и т.д.)
Я не утруждал себя, стилистическими красивостями, поэтому сначала, объявим методы нашего класса. В отличии от функций для объявление используется макрос PHP_METHOD с двумя параметрами, первым из которых идёт имя класса CFoo, вторым имя метода. Объявив метод __construct, не значит на самом деле что он будет конструктором, вообще, я не экспериментировал, но наверно любой метод можно назвать конструктором, для этого необходимо воспользоваться как и в случае с обыкновенными функциями, структурой zend_function_entry.
Но тут уже есть отличие, небольшое, методы объявляются не макросом PHP_FE, а PHP_ME, в котором появились некоторые параметры, нас интересует первый и последний, ну и второй. Первый как понятно, это имя нашего класса, второй имя метода, последний самый интересный, флаги метода, определяет область видимости метода, а также некоторые замечательные свойства, такие как ZEND_ACC_CTOR - указывает, что данный метод является конструктором. Подробнее про флаги можно посмотреть в файлке zend_compile.h, на что влияют перечисленные флаги, можно судить по названиям. Итак, таблица методов определена.
Приступаем к регистрации нашего класса, все это дело производится при загрузке модуля в функции PHP_MINIT_FUNCTION. Что тут мы делаем, используя макрос INIT_CLASS_ENTRY, конструируем наш класс, второй параметр имя класса, третьим параметром, таблица методов класса. И напоследок, регестрируем его в глобальной таблице классов PHP. (проверку я сознательно опустил)
Данный метод, понятно что делает! В phpinfo() информацию о экстеншене.
Ну и напоследок, определим структуру для модуля, но тут надо обратить внимание (я, очень долго мучился, потому, как вылетали исключения при работе с реализованным классом в одном из проектов), в обычных экстеншенах используется макрос STANDARD_MODULE_HEADER и STANDARD_MODULE_PROPERTIES, для определения default свойств структуры, в нашем же случае, используется STANDARD_MODULE_HEADER_EX и STANDARD_MODULE_PROPERTIES_EX. Впринципе ничего страшно не произойдёт, если класс не будет использовать Resource и Extra данные, в противном случае могут быть проблемы. (возможно, это надумано, но все проблемы с памятью решились, когда я поставил эти макросы)
Ну впринципе все. Нас ждет последовательный вызов ./buildconf - дабы сообщить, что нужно в конфиг внести наш экстеншен и ./configure --enable-cfoo=shared - сборщик обрадуется ). make - дабы собрать это все дело. Если все удачно получилось (у меня да
), то должен появиться файлик php_foo(.dll|.so). Не забудем прописать его в php.ini
У меня вывелось "Hello CFoo". А у Вас?
Далее (использование Extra совместно с объектом класса, что это и как с ним работать).
Реализация классов в PHP5 экстеншене:
Я не претендую на полноту изложения, возможно предложенные подходы и отличаются от принятых подходов разработчиков PHP, но вакуум который создался в отношении реализации классов в экстеншенах, мне бы хотелось хоть как-то заполнить. Каждый может заполнить по своему и надеюсь, пост натолкнёт Вас на более продвинутые мысли и свои способы реализации.
В основном это рассчитано, на тех кто уже знаком с написанием экстеншенов. Если конечно пост удасться, и будет в этом желание, то могу наверно написать, еще так сказать и азы.
PS: Я отлаживаю экстеншены под Windows используя Visual Studio, ничего не имею против Linux-а, просто мне удобней. Весь код является кросплатформенным и компилируется как под Windwos, так и под Linux, как с консоли, так и с помощью KDevelop и VS, но настройку проектов под KDev и VS я опущу (это отдельная история).
Рассматривать буду на живом примере, в смысле который потом можно скомпилировать, так сказать пошагово. Внимание заострено, на классах, поэтому многие вещи, такие как настройки php.ini, глобальные переменные модуля и т.д., опущены.
1. Структура проекта
php_foo.h
php_foo.c
config.m4
config.w32
2. config.m4 - определяет параметры, файлы экстеншена, для компиляции
PHP:
dnl
dnl $Id: config.m4,v 1.6 2002/03/12 16:10:56 sas Exp $
dnl
PHP_ARG_ENABLE(cfoo,enable CFoo class,
[ --enable-cfoo Enable support for CFoo])
if test "$PHP_CFOO" = "yes"; then
AC_DEFINE(HAVE_CFOO,1,[ ])
PHP_NEW_EXTENSION(cfoo, php_foo.c, $ext_shared)
fi
PHP:
// $Id: config.w32,v 1.1 2003/12/02 23:16:49 wez Exp $
// vim:ft=javascript
ARG_ENABLE("cfoo", "Enable support for CFoo", "no");
if (PHP_CFOO == "yes") {
EXTENSION("cfoo", "php_foo.c");
AC_DEFINE('HAVE_CFOO', 1, 'Have CFoo');
}
PHP:
#ifndef PHP_CFOO_EXT
#define PHP_CFOO_EXT
#include "php.h"
#include "zend_API.h"
#include "php_ini.h"
#define EXT_VERSION "0.0.1"
#define EXT_NAME "CFOO"
#define EXT_VERSION_STRING (EXT_NAME EXT_VERSION " (PHP " PHP_VERSION ")")
#define EXT_AUTHOR "A.Yakubouski"
#define EXT_URL "http://localhost"
#define EXT_COPYRIGHT "Irokez (c)"
#endif//PHP_CFOO_EXT
PHP:
#include "php_foo.h"
PHP:
zend_class_entry* g_ClassEntry;
zend_object_handlers g_ClassHandlers;
PHP:
PHP_METHOD(CFoo, __construct)
{
}
PHP_METHOD(CFoo,get)
{
RETURN_STRINGL("Hello CFoo",10,1);
}
PHP:
zend_function_entry class_methods[] = {
PHP_ME(CFoo,__construct,NULL, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
PHP_ME(CFoo,get,NULL, 0)
{NULL, NULL, NULL}
};
PHP:
PHP_MINIT_FUNCTION(cfoo)
{
zend_class_entry stubClassEntry;
INIT_CLASS_ENTRY(stubClassEntry,"CFoo",class_methods);
g_ClassEntry = zend_register_internal_class(&stubClassEntry TSRMLS_CC);
return SUCCESS;
}
PHP:
PHP_MINFO_FUNCTION(cfoo)
{
php_info_print_table_start();
php_info_print_table_header(2, EXT_NAME, "loaded");
php_info_print_table_row(2, "Version", EXT_VERSION);
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
PHP:
zend_module_entry cfoo_module_entry =
{
STANDARD_MODULE_HEADER_EX,
NULL,
NULL,
"cfoo",
NULL,
PHP_MINIT (cfoo),
NULL,
NULL,
NULL,
PHP_MINFO (cfoo),
EXT_VERSION,
NULL,
NULL,
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
ZEND_GET_MODULE(cfoo)

PHP:
<?php
$foo = new CFoo;
echo $foo->get();
?>
Далее (использование Extra совместно с объектом класса, что это и как с ним работать).