Реализация классов в PHP5 экстеншене, часть 3
Вот и подошла наверно очередь и третьей заключительной части по реализации классов в экстеншенах. В ней будет рассмотрен вопрос о связывании указателя this с произвольной С структурой, "перегрузкой" метода создания объекта класса и вкратце ряда предопределённых методов (__call, __set, __get, __clone).
На практике, при разработке класса в экстеншене, не всегда удобно хранить значения переменных в zval- структурах. Для связывания неявного указателя this и произвольной С структуры предусмотрен специальный механизм, называемый 'objects storage', но воспользоваться можно им имея указатель на экземпляр класса.
Начнём по порядку, прежде чем связать объект со структурой, давайте перегрузим метод, отвечающий за создание экземпляра класса, а именно "new". Для этого вернёмся к определённой нами функции PHP_MINIT_FUNCTION(cfoo) и добавим в неё всего лишь одну строчку:
Теперь нам необходимо определить саму функцию CFoo_New, дабы контролировать процесс
.
Рассмотрим, произошедшее в деталях. CFoo_Extra - как не трудно догадаться, это и есть наша произвольная C структура, произвольная она в некотором смысле, потому как в ней должна быть обязательная предопределённая информация:
распределяем место, под нашу структуру, инициализируем объект класса в нашей структуре zend_object_std_init, копируем свойства zend_hash_copy, тут вроде как все понятно. Далее инициализируем саму структуру. Вот после этого самое интересное, запихиваем наш объектик в "objects storage". zend_objects_store_put, первый параметр, указатель на нашу структуру, второй, указатель на деструктор объекта класса, а вот третий параметр, деструктор нашего объектика CFoo_Delete ( мы же не хотим иметь в своем экстеншене memory leakes )
После того, как добавили все для работы с нашими экстра данными класса, наверно необходимо как-то получать к ним доступ из наших методов, все что нам для этого надо, как говорилось выше, иметь лишь указатель на объект (this).
Вот собственно и все
.
Как всегда, исходники того что было сделано.
foo 2008.03.21 10.01.rar 8Кб
Практически аналогично, перегружаются все предопределённые методы, и наверно нет необходимости копи-пастить их здесь
Спасибо, всем кто читал, кому это было интересно. Я не претендую и 100% корректность терминов и надеюсь что хоть кому-то, мои исследования помогут в создании своих суппер-экстнешенов. Ещё раз спасибо за внимание.
Вот и подошла наверно очередь и третьей заключительной части по реализации классов в экстеншенах. В ней будет рассмотрен вопрос о связывании указателя this с произвольной С структурой, "перегрузкой" метода создания объекта класса и вкратце ряда предопределённых методов (__call, __set, __get, __clone).
На практике, при разработке класса в экстеншене, не всегда удобно хранить значения переменных в zval- структурах. Для связывания неявного указателя this и произвольной С структуры предусмотрен специальный механизм, называемый 'objects storage', но воспользоваться можно им имея указатель на экземпляр класса.
Начнём по порядку, прежде чем связать объект со структурой, давайте перегрузим метод, отвечающий за создание экземпляра класса, а именно "new". Для этого вернёмся к определённой нами функции PHP_MINIT_FUNCTION(cfoo) и добавим в неё всего лишь одну строчку:
PHP:
PHP_MINIT_FUNCTION(cfoo)
{
zend_class_entry stubClassEntry;
INIT_CLASS_ENTRY(stubClassEntry,"CFoo",class_methods);
/* Собственно это и есть перегрузка функции отвечающей за создание объекта */
stubClassEntry.create_object = CFoo_New;
g_ClassEntry = zend_register_internal_class(&stubClassEntry TSRMLS_CC);
zend_declare_property_string(g_ClassEntry,"var",3,"Hello CFoo",ZEND_ACC_PRIVATE TSRMLS_CC);
zend_declare_property_long(g_ClassEntry,"long_var",8,54321,ZEND_ACC_PUBLIC TSRMLS_CC);
zend_declare_property_long(g_ClassEntry,"static_var",10,5,ZEND_ACC_PUBLIC|ZEND_ACC_STATIC TSRMLS_CC);
return SUCCESS;
}

PHP:
zend_object_value CFoo_New(zend_class_entry *class_type TSRMLS_DC)
{
CFoo_Extra *intern;
zend_object_value retval;
zval tmp;
intern = emalloc(sizeof(CFoo_Extra));
zend_object_std_init(&intern->сlassInstance, class_type TSRMLS_CC);
zend_hash_copy(intern->сlassInstance.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
intern->classExtraInt = 45;
intern->classExtraStr = "CFoo Extra C structure";
retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) CFoo_Delete, NULL TSRMLS_CC);
retval.handlers = &((g_ClassHandlers));
return retval;
}
PHP:
typedef struct _CFoo_Extra {
zend_object сlassInstance; // Именно это она и есть.
int classExtraInt;
char* classExtraStr;
} CFoo_Extra;
PHP:
void CFoo_Delete(void *object TSRMLS_DC)
{
CFoo_Extra *intern = (CFoo_Extra *)object;
intern->classExtraInt = 0;
intern->classExtraStr = NULL;
zend_object_std_dtor(&intern->classInstance TSRMLS_CC);
efree(object);
}
PHP:
CFoo_Extra* ExThis = (CFoo_Extra*)zend_object_store_get_object(getThis() TSRMLS_CC);

Как всегда, исходники того что было сделано.
foo 2008.03.21 10.01.rar 8Кб
Практически аналогично, перегружаются все предопределённые методы, и наверно нет необходимости копи-пастить их здесь

Спасибо, всем кто читал, кому это было интересно. Я не претендую и 100% корректность терминов и надеюсь что хоть кому-то, мои исследования помогут в создании своих суппер-экстнешенов. Ещё раз спасибо за внимание.