/** * php-asio/p3.hpp * * This header is a simple helper for wrapping C++ classes, * which is borrowed from https://github.com/phplang/p3. * The casting/cloning/comparing functionalities are removed, * because they are not needed by php-asio. */ #pragma once #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #define P3_METHOD_DECLARE(name) \ void zim_##name(INTERNAL_FUNCTION_PARAMETERS) #define P3_METHOD(cls, name) \ void cls::zim_##name(INTERNAL_FUNCTION_PARAMETERS) #define P3_ME(cls, name, meth, arginfo, flags) \ ZEND_FENTRY(name, [](INTERNAL_FUNCTION_PARAMETERS) { \ ::p3::to_object(getThis())->zim_##meth(INTERNAL_FUNCTION_PARAM_PASSTHRU); \ }, arginfo, flags) #define P3_ME_D(cls, meth, arginfo, flags) \ P3_ME(cls, meth, meth, arginfo, flags) #define P3_STATIC_ME(cls, meth, arginfo, flags) \ ZEND_FENTRY(meth, &cls::zim_##meth, arginfo, flags | ZEND_ACC_STATIC) #define P3_ABSTRACT_ME(name, arginfo) \ PHP_ABSTRACT_ME("", name, arginfo) namespace p3 { /// Native object to Zend object. template zend_object* to_zend_object(T* obj) { return reinterpret_cast(obj + 1); } /// Zend object to native object. template T* to_object(zend_object* obj) { return reinterpret_cast(obj) - 1; } /// Zval to native object. template T* to_object(zval* obj) { return reinterpret_cast(Z_OBJ_P(obj)) - 1; } /// Allocate new object. template zend_object* alloc_object(zend_class_entry* ce, InitFunc init) { auto ptr = reinterpret_cast(ecalloc(1, sizeof(T) + sizeof(zend_object) + zend_object_properties_size(ce))); init(ptr); auto zobj = to_zend_object(ptr); zend_object_std_init(zobj, ce); zobj->handlers = &T::handlers; return zobj; } /// Allocate new object with default constructor. template typename std::enable_if::value, zend_object*>::type create_object(zend_class_entry* ce) { return alloc_object(ce, [](T* ptr) { new(ptr) T(); }); } template typename std::enable_if::value, zend_object*>::type create_object(zend_class_entry* ce) { assert(false); return nullptr; } /// Destroy an object. template void dtor_object(zend_object *obj) { zend_object_std_dtor(obj); to_object(obj)->~T(); } /// Fail to create object if there's no default constructor. inline zend_object* create_object_fail(zend_class_entry* ce) { php_error_docref(nullptr, E_ERROR, "%s should not be directly instantiated.", ZSTR_VAL(ce->name)); return zend_objects_new(ce); } template zend_class_entry* class_init(const char* name, const zend_function_entry* methods) { zend_class_entry ce; INIT_CLASS_ENTRY_EX(ce, name, strlen(name), methods); T::class_entry = zend_register_internal_class(&ce); T::class_entry->create_object = std::is_constructible::value ? create_object : create_object_fail; memcpy(&T::handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); T::handlers.offset = sizeof(T); T::handlers.free_obj = dtor_object; T::handlers.clone_obj = nullptr; return T::class_entry; } inline zend_class_entry* interface_init(const char* name, const zend_function_entry* methods) { zend_class_entry ce; INIT_CLASS_ENTRY_EX(ce, name, strlen(name), methods); return zend_register_internal_interface(&ce); } }