Реализация классов в PHP5 экстеншене, пример, надеюсь с подробным объяснением

Ирокез

бессмертный пони
Команда форума
Партнер клуба
Реализация классов в 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 - определяет параметры, файлы экстеншена, для компиляции
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
3. config.w32 - этот файл конфигурации нужен для компиляции экстеншена под Windows
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');
	}
4. php_foo.h - заголовочный файл проекта
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
5. php_foo.c - непосредственно реализация тела модуля и класса
PHP:
	#include "php_foo.h"
Объявляем несколько глобальных переменных, в первой из них g_ClassEntry, будет находиться адрес класса зарегистрированного в глобальной таблице классов php, на случай, если нам понадобиться обратиться к нему. Во вторую переменную, после регистрации, скопируем адреса стандартных функций обработчиков (__get,__set,__clone и т.д.)
PHP:
	zend_class_entry*	g_ClassEntry;
	zend_object_handlers	g_ClassHandlers;
Я не утруждал себя, стилистическими красивостями, поэтому сначала, объявим методы нашего класса. В отличии от функций для объявление используется макрос PHP_METHOD с двумя параметрами, первым из которых идёт имя класса CFoo, вторым имя метода. Объявив метод __construct, не значит на самом деле что он будет конструктором, вообще, я не экспериментировал, но наверно любой метод можно назвать конструктором, для этого необходимо воспользоваться как и в случае с обыкновенными функциями, структурой zend_function_entry.
PHP:
	PHP_METHOD(CFoo, __construct)
	{
	}
	
	
	PHP_METHOD(CFoo,get)
	{
		RETURN_STRINGL("Hello CFoo",10,1);
	}
Но тут уже есть отличие, небольшое, методы объявляются не макросом PHP_FE, а PHP_ME, в котором появились некоторые параметры, нас интересует первый и последний, ну и второй. Первый как понятно, это имя нашего класса, второй имя метода, последний самый интересный, флаги метода, определяет область видимости метода, а также некоторые замечательные свойства, такие как ZEND_ACC_CTOR - указывает, что данный метод является конструктором. Подробнее про флаги можно посмотреть в файлке zend_compile.h, на что влияют перечисленные флаги, можно судить по названиям. Итак, таблица методов определена.
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_MINIT_FUNCTION. Что тут мы делаем, используя макрос INIT_CLASS_ENTRY, конструируем наш класс, второй параметр имя класса, третьим параметром, таблица методов класса. И напоследок, регестрируем его в глобальной таблице классов PHP. (проверку я сознательно опустил)
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;
	}
Данный метод, понятно что делает! В phpinfo() информацию о экстеншене.
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();
	}
Ну и напоследок, определим структуру для модуля, но тут надо обратить внимание (я, очень долго мучился, потому, как вылетали исключения при работе с реализованным классом в одном из проектов), в обычных экстеншенах используется макрос STANDARD_MODULE_HEADER и STANDARD_MODULE_PROPERTIES, для определения default свойств структуры, в нашем же случае, используется STANDARD_MODULE_HEADER_EX и STANDARD_MODULE_PROPERTIES_EX. Впринципе ничего страшно не произойдёт, если класс не будет использовать Resource и Extra данные, в противном случае могут быть проблемы. (возможно, это надумано, но все проблемы с памятью решились, когда я поставил эти макросы)
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)
Ну впринципе все. Нас ждет последовательный вызов ./buildconf - дабы сообщить, что нужно в конфиг внести наш экстеншен и ./configure --enable-cfoo=shared - сборщик обрадуется ). make - дабы собрать это все дело. Если все удачно получилось (у меня да :)), то должен появиться файлик php_foo(.dll|.so). Не забудем прописать его в php.ini

PHP:
<?php
$foo = new CFoo;
echo $foo->get();
?>
У меня вывелось "Hello CFoo". А у Вас?

Далее (использование Extra совместно с объектом класса, что это и как с ним работать).
 

phprus

Moderator
Команда форума
Может быть эту тему перенести в "PEAR/Smarty, PECL & другие модули PHP"?
ИМХО в том разделе она будет уместнее чем в оффтопике, особенно с учетом того в в описании раздела модули фигурирует создание собственных модулей.

Ирокез
Хорошая, и, я думаю, полезная для начинающих статья.
Спасибо.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
спасибо!
давно хотел понять :)

кстати, где бы посмотреть реализацию констант и массивов?
 

tony2001

TeaM PHPClub
констант - в любом экстеншене, который декларирует константы.
см. его MINIT

массивов - в любой функции, которая работает с массивами.
 

Baranov_Dron

Новичок
экстеншен я правильно понял, что это какая-то прибалута Zend фрэймворка?
 

Alexandre

PHPПенсионер
экстеншен я правильно понял, что это какая-то прибалута Zend фрэймворка?
вот Zend фрэймворк здесь действительно непричем.
экстеншен - это написание на Си собственных функций и классов.
 

Sherman

Mephi
Re: Реализация классов в PHP5 экстеншене, пример, надеюсь с подробным объяснением

Автор оригинала: Ирокез
PS: Я отлаживаю экстеншены под Windows используя Visual Studio, ничего не имею против Linux-а, просто мне удобней. Весь код является кросплатформенным и компилируется как под Windwos, так и под Linux, как с консоли, так и с помощью KDevelop и VS, но настройку проектов под KDev и VS я опущу (это отдельная история).
Ну вроде ничего сложного.

Могу описать как это делается под Eclipse CDT v. 3.4.1(одним из способов).

1. В директории с исходниками extension делаем phpize.

2. Запускаем в этой директории ./configure.

3. В Eclipse CDT создаем новый пустой проект типа "С Project".

4. После создания делаем import из FileSystem. Указываем директорию с исходниками.

5. В настройках проекта С/C++ Build снимаем галку "Use default build command" и пишем в "Build command": "make". Также снимем галку "Generate Makefiles automatically" и пишем в "Build Location": "${workspace_loc:/project dir}".

6. Делаем ctrl+b и наслаждаемся :)
 

nerezus

Вселенский отказник
А как компилировать этот екстеншн под виндой?
 

Forux

Новичок
Доброго времени суток,

увы все ссылки на исходники в 4 темах не рабочие, по этому вопросы:

1. актуальна ли данная информация сейчас?

2. где можно как можно детальнее ознакомиться с созданием модулей для пхп (и под юникс и под вин) ?

П.С. не могу понять чем компилировать данный пример.
 

craz

Нестандартное звание
блин чето прикольное подержите до завтра посещаемым..
очень интересно почитать
 

Ирокез

бессмертный пони
Команда форума
Партнер клуба
Если надо, могу выслать исходники. компилировать можно из консоли так и из VS. в линуксе ./phpize, ./configure --enable-....., make
 

Forux

Новичок
при если не сложно (мыло [email protected])

то есть там будет мейк файл? А от пхп какие то файлы нужны дополнительно?
 

sergej-123

Новичок
Добрый день,
Делал аналогично по туториалам. Проблем собрать свой extension нет. Проблема у меня в следующем: необходимо подключить стороннюю библиотеку, при сборке непосредственно исполняемого файла проблем нет, а при сборке экстеншена через phpize, configure и make библиотека не подключается в принципе. Пробовал копать в сторону файлов configure и Makefile, но ничего не получается. Кто-нибудь может помочь в решении проблемы?
 

sergej-123

Новичок
В общем понятно, что я не правильно делаю, config.m4 тестового примера, который я нашел, не подходит. Сейчас вот такой был:
PHP:
PHP_ARG_ENABLE(hello, whether to enable Hello World support,
[ --enable-hello Enable Hello World support])

if test "$PHP_HELLO" = "yes"; then
AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World])
PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)
fi
Подскажите пожалуйста с какими параметрами необходимо запускать configure, чтобы подключить so-шку?
 

tony2001

TeaM PHPClub
ни с какими.
у тебя она не подключается.
я тебе дал ссылку на причем config.m4, где подключается либа.
 

sergej-123

Новичок
tony2001
В общем дуб-дубом я в этом :(

есть библиотека libmesprox.so, выложенная в /lib, можете помочь написать автоконфиг, чтобы сформировать конечную so-шку?
 
Сверху