Currently, PHP extensions that have dependencies on other extensions use compile-time configure checks to verify availability. This has several problems:
-
Load order is important, as loading the dependency after the dependent extension also triggers symbol errors.
Upgrading an extension can easily break binary compatibility creating undefined behavior.
The errors given to the end-user are not always obvious or easy for them to debug.
On systems where symbols are resolved lazily, the error will not manifest until the code path is executed. This makes debugging difficult, and unexpected.
The
API functions will be passed via a extension specific structure containing function pointers. This requires that extenions share a common prototype for via a C header file. Getting the correct prototype for the correct
API version will of course be critical.
During module initialization the extension will provide a set of
API structures that it supports that contain the function pointers. This can be called multiple times with different version numbers.
The extension can also request an
API structure for a specific extension and
API version at module initialization. The problem of extension load order needs to be solved here, as returning the
API structure will likely need to be delayed until after module initialization but not before request initialization to avoid incurring this cost on every request.
It may be useful if this interface can be used by
PHP to expose callback hooks or interfaces to extensions that may change in the future or need to be abstracted for extension use.
Having the ability to list dependencies of extensions, and exposed
API's could be useful for informational purposes and documentation.
/* expose API to other extensions
* we'll be exposing a fetch() function and a store() function
* from our extension. This could be any calls we want to expose.
* extension_api_t is a custom structure for this extension with
* function pointers defining this extension's API.
*/
struct extension_api_t api;
api.version = 1;
api.fetch = my_fetch;
api.store = my_store;
php_register_api(&api)
/* fetch external extension API */
int rval;
int version = 2;
struct extension_api_t *api;
rval = php_get_api('myextension', version, &api);
if (rval == PHP_EXT_UNAVAIL) {
zend_error(E_WARNING, "myextension is not loaded or available, disabling feature");
return NULL;
} else if (rval == PHP_EXT_NOVERSION) {
zend_error(E_WARNING, "myextension version %d is required, disabling feature", version);
return NULL;
} else {
return api->fetch(key);
}