Концепт метасистемы PHPQt5
PostPosted: 27 Mar 2016, 08:38
Смотрел исходники генерируемые метакомпилятором Qt для классов, интересовал в основном процесс вызова методов по их имени.
Оказалось все довольно просто: есть список имён методов (обычные строки, представляете? даже не адреса функций, а просто имена), каждому методу присвоен свой индекс.
Перед вызовом "метасистема" ищет нужный индекс по сигнатуре метода: methodName(argType0,argtype1,argType2),
а потом просто обращается к статической функции для вызова, в которую передаются указатель на объект, индекс функции и набор аргументов.
А в этой статической функции!!! Бугагашеньки
В настоящей реализации она и используется. Но оригинальные классы Qt имеют очень, не побоюсь этого слова, скудную мета-информацию, и предоставляют доступ метасистеме только к наиболее востребованным методам. Для того чтобы открыть доступ ко всем методам, необходимо создавать обёртку и переопределять все методы, устанавливая им флаг "виден для метасистемы".
При этом для вызова конкретного метода необходимо подготовить набор аргументов к их передачи: т.е. нужно произвести их проверку, произвести возможные преобразования и только потом отправить в вызов. В собственной реализации этот момент можно будет обыграть заранее, упростив его до минимума.
Как я вижу реализацию метасистемы PHPQt5?
Вся магия будет в макросах, т.е. минимум кода. Не нужно будет самостоятельно составлять функцию со списком методов, нужно будет просто перечислить методы в макросах, а макросы, распаковавшись прекомпилятором, создадут валидные тела функций.
К примеру, я хочу создать обертку для QTimer:
Буду развивать эту идею, попутно экспериментировать. Возможно в будущем движок приобретёт новый облик :)
п.с. на стороне php ничего не изменится.
Оказалось все довольно просто: есть список имён методов (обычные строки, представляете? даже не адреса функций, а просто имена), каждому методу присвоен свой индекс.
Перед вызовом "метасистема" ищет нужный индекс по сигнатуре метода: methodName(argType0,argtype1,argType2),
а потом просто обращается к статической функции для вызова, в которую передаются указатель на объект, индекс функции и набор аргументов.
А в этой статической функции!!! Бугагашеньки
- Code:
static_metacall(object, index, params) { PQObject *_t = static_cast<PQObject *>(object); switch (_id) { case 0: _t->setObjectName((*reinterpret_cast< QString(*)>(_a[1]))); break; case 1: { QVariant _r = _t->getUserProperty((*reinterpret_cast< const QString(*)>(_a[1]))); if (_a[0]) *reinterpret_cast< QVariant*>(_a[0]) = _r; } break; case 2: { QString _r = _t->objectName(); if (_a[0]) *reinterpret_cast< QString*>(_a[0]) = _r; } break; /* и так далее весь список методов QObject */ }
- во первых: избавится от обёрток для методов (от обёрток для классов избавится все-же не получится);
- во вторых: избавится от проблем с кастованием типов;
- в третьих: значительно ускорить вызовы методов;
- в четвертых: значительно упростить создание обёрток, фактически все сведётся только к описанию всех методов в заголовочном файле, создавать тела методов уже будет не нужно.
В настоящей реализации она и используется. Но оригинальные классы Qt имеют очень, не побоюсь этого слова, скудную мета-информацию, и предоставляют доступ метасистеме только к наиболее востребованным методам. Для того чтобы открыть доступ ко всем методам, необходимо создавать обёртку и переопределять все методы, устанавливая им флаг "виден для метасистемы".
При этом для вызова конкретного метода необходимо подготовить набор аргументов к их передачи: т.е. нужно произвести их проверку, произвести возможные преобразования и только потом отправить в вызов. В собственной реализации этот момент можно будет обыграть заранее, упростив его до минимума.
Как я вижу реализацию метасистемы PHPQt5?
Вся магия будет в макросах, т.е. минимум кода. Не нужно будет самостоятельно составлять функцию со списком методов, нужно будет просто перечислить методы в макросах, а макросы, распаковавшись прекомпилятором, создадут валидные тела функций.
К примеру, я хочу создать обертку для QTimer:
- Code:
class PQTimer : public QTimer { Q_OBJECT // инициализация местасистемы Qt PQ_OBJECT // инициализация местасистемы PHPQt5 // #define PQ_METHOD(returnType, methodName, paramType1) PQ_META_METHODS_START { // распакуется в pq_static_metacall(QObject *object, int methodIndex, void **params) { PQTimer *pobject = static_cast<PQTimer *>(object); switch(methodIndex) { PQ_METHOD_1(void, setInterval, int); // распакуется в 0: pobject->setInterval( (*reinterpret_cast<int>(params[0])) ); PQ_METHOD_0(void, start); // распакуется в 1: pobject->start(); } PQ_META_METHODS_END // распакуется в }} }
Буду развивать эту идею, попутно экспериментировать. Возможно в будущем движок приобретёт новый облик :)
п.с. на стороне php ничего не изменится.