ideas:dependencyinterfaceapi

Abstract Extension API and Dependency Interface

Possible mentors: Brian Shire, Andrei Zmievski

Description

Currently, PHP extensions that have dependencies on other extensions use compile-time configure checks to verify availability. This has several problems:

  • Any dependency that is not available will trigger undefined symbol errors, likely at run-time, see: http://marc.info/?l=php-internals&m=123456185115526&w=2.
  • 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.

Deliverables

  • Develop functionality for PHP that will allow extensions to register a set of functions as a versioned API.
  • Other extensions should be able to fetch this API, or handle failures appropriately for their application such as disabling features or generating an error. This includes dependencies being unavailable, or not having the expected version. The calling extension should be able to differentiate between these conditions.
  • The interface should support extensions being loaded in any order.
  • Extensions should be able to support multiple API versions at the same time for backwards compatibility.

Initial Brainstorming and Design

  • 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);
}

Status

Unknown.

Progress

Unknown.

ideas/dependencyinterfaceapi.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1