====== Abstract Extension API and Dependency Interface ====== * The original application is [[http://socghop.appspot.com/student_project/show/google/gsoc2009/php/t124023314420]] * For those who don't have access - [[http://www.xvpj.net/gsoc-09-application-php-abstract-extension-api-and-dependency-interface/]] ===== Details ===== * Student: Varuna Jayasiri * Mentor: shire * Timezone: GMT +5:30 (Varuna) * Mailing list: pecl-dev@lists.php.net ===== Abstract ===== The objective of this project is to develop functionality for PHP that will allow extensions to register a set of functions as a versioned API, since PHP does not currently handle interdependencies among PHP extensions well, which leads to various problems. This would also solve the current problem of extension load order. ===== Documentation ===== ==== Versioning ==== Versions are in the format major.minor[.build[.revision]] in the string representation. These are stored in unsigned integers for ease of searching. The first 8 bits are used for the major, next 8 for the minor, next 8 for the build and the last 8 bits for the revision. It is possible to convert from the string representation to an unsigned integer using zend_eapi_toi and from an unsigned integer to the string format using zend_eapi_toa function. ==== Macros ==== EAPI_SET_CALLBACK(ext_name, version, callback) Sets a callback - with reference to a extension and a version - should be called during MINIT. The callback will be called after all extensions have been initialized. Callback will be called with a reference to the API of the specified extension. See zend_eapi_set_callback. ^ ''ext_name'' | Extension name | ^ ''version'' | Version - if a null value will is passed the callback will be called with the latest version | ^ ''callback'' | Function pointer to the callback function | EAPI_SET_EMPTY_CALLBACK(callback) Sets an empty callback - should be called during MINIT. The callback will be called after all extensions have been initialized. See zend_eapi_set_empty_callback. ^ ''callback'' | Function pointer to the callback function | EAPI_CALLBACK_FUNCTION(callback) Defines the callback function. The callback function will be called with the following parameters: type, module_number, api (pointer to the api), ext_name, version, ^ ''callback'' | Name of the callback function | EAPI_EMPTY_CALLBACK_FUNCTION(callback) Defines the empty callback function. The callback function will be called with the following parameters: typei and module_number, ^ ''callback'' | Name of the callback function | ==== Functions ==== All functions return ''SUCCESS'' on success and ''FAILURE'' on failure. int zend_eapi_register(char *ext_name, char * version_text, void *api, size_t size) Registers an API ^ ''ext_name'' | Extension name | ^ ''version'' | API version in format major.minor[.build[.revision]] | ^ ''api'' | A ponter to the API structure | ^ ''size'' | Size of the API structure | int zend_eapi_version_toi(char *version_text, uint *version_int) Converts a version in text format to an integer. ^ ''version_text'' | Version as a string | ^ ''version_int'' | Version as a numerical value | int zend_eapi_version_toa(uint version, char * version_text) Converts a version in integer format to a string ^ ''version_text'' | Version as a string | ^ ''version_int'' | Version as a numerical value | int zend_eapi_find_versions(char *ext_name, uint version, uint mask, uint *result, int *size, int buf_length) Finds the set of versions available. Matches versions if ''(extension_version & mask) == (version & mask)''. ^ ''ext_name'' | Extension name | ^ ''version'' | Version to be searched for | ^ ''mask'' | A mask to specify which part of version should be matched | ^ ''result'' | Pointer to an array, which will be filled with matched versions | ^ ''size'' | Number of matches found | ^ ''buf_length'' | Capacity of the array results (memory allocated) | int zend_eapi_get_latest_version(char *ext_name, uint *version) Gives the latest version of the extension available ^ ''ext_name'' | Extension name | ^ ''version'' | Latest version as a numerical value | int zend_eapi_exists(char *ext_name, char *version) Checks if the API is available ^ ''ext_name'' | Extension name | ^ ''version'' | Version | int zend_eapi_get(char *ext_name, char *version, void **api) Retrieves the API ^ ''ext_name'' | Extension name | ^ ''version'' | Version | ^ ''api'' | API will be loaded here if it is available | int zend_eapi_set_empty_callback(int type, int module_number, void (*callback)(EMPTY_CALLBACK_FUNC_ARGS)) Sets an empty callback - should be called during MINIT. The callback will be called after all extensions have been initialized. Use EAPI_SET_EMPTY_CALLBACK. ^ ''callback'' | Function pointer to the callback function | int zend_eapi_set_callback(int type, int module_number, char *ext_name, char *version, void (*callback_func)(CALLBACK_FUNC_ARGS)) Sets a callback - with reference to a extension and a version - should be called during MINIT. The callback will be called after all extensions have been initialized. Callback will be called with a reference to the API of the specified extension. Use EAPI_SET_CALLBACK. ^ ''ext_name'' | Extension name | ^ ''version'' | Version - if a null value will is passed the callback will be called with the latest version | ^ ''callback'' | Function pointer to the callback function | ===== Timeline ===== 20th April to 23rd May – Community bonding period * Getting more familiarized with PHP core and Zend * Submitting the proposed API and design for suggestions * Getting ideas from the developer community on how this should be developed * Finalizing the design 23rd May to 1st July – Implementing most important features * The API registration and retrieval component will be developed * The interface for setting up the callback function will not be implemented at this stage, instead a simpler interface (e.g. php_get_api) would be provided * Code written will be unit tested * This would be a standard to be distributed for testing 1st July to 10th July – Testing the implemented section * The implemented features will be tested with help from the community * Any bugs encountered will be fixed * Any suggestions for improvements will be considered and implemented 10th July to 1st August – Completing the implementation of all features * All the functionality described above will be completed * Code written will be unit tested * Behavior of the component in various scenarios with interdependencies among extensions, will be tested thoroughly 1st August to 4th August – Buffer * Small buffer period so that any additional things that come up in the way could be implemented or if time taken for implementation exceeds time estimated * The completed extension API and dependency interface will be made available for the developer community * Any improvements suggested will be considered and implemented 4th August to 17th August – Testing * Any bug fixes will be implemented * All documentations will be completed * It will be ready for distribution at the end of testing ===== Progress ===== == 12th May == * Setup the development environment * Working on the GIT repository - [[git://github.com/vpj/PHP-Extension-API.git]] * Made a few changes to the proposed design * All the code will be a part of zend and hence all function will be prefixed with zend_ and not php_ * Prefixed all the functions with zend_ext_api instead of function names like php_register_api == 15th May == * Discussing how different versions of API's should be maintained * Coded the basic functionality * Memory leaks and exception handling were not considered (TODO's were added to make sure these will be addressed later) == 23rd May == * Two hashtables are used - one to store the API's and the other to store the available versions * A simple list is used to store the set of versions available * Versions are represented in major.minor[.build[.revision]] or major.minor[.maintenance[.build]] formats; i.e. "x.x.x.x" * These are converted to a 32 bit integer for indexing * Bit masks could be used to identify ranges of versions easily == 31st May == * Included a function to get the latest version of an extension available * Functions to convert version from major.minor[.build[.revision]] format to an uint and vice versa are provided. * when representing the version in uint first 8 bits will be used for major and the next 8 for minor and so on * A few memory leaks were fixed == 5th June == * Added some documentation of the interface * Did some testing == 27th June == * Coded the callback registration * Callbacks are called from php_module_startup (main/main.c) * Tested callbacks * Update sample usage code == 10th July == * Callbacks * Module number is passed to the callback * Callbacks can be registered for the latest API version * Testing * Two extension with a set of standard unit test cases were added to the git repository * API interface was tested with the extensions mbstring and exif * Name * eapi is used instead of ext_api == 20th July == * Callbacks with no extension specified * Used dependency interface on mbstring/exif == 31st July == * Setting callbacks accept module_number / type (through macros) * Callbacks are called with module_number / type. e.g. usage - INIs could be registered from the callback * Functions to search versions of an extension * Example usage of the dependency interface : [[http://www.xvpj.net/2009/06/26/how-to-use-php-extension-api-dependancy-interface/]] * How dependency interface is implemented on mbstring / exif : [[http://www.xvpj.net/2009/07/29/eapi2/]] == 16th August == * Received some suggestions from the community (mailing list) * Fixed a problem with win32 build - included zend_eapi.c in config.w32 * TSRMLS parameters are passed to callbacks to improve performance * Added support for extensions loaded through dl() * When a extension (say ext_dl) is loaded through dl() the callbacks of other extensions (already loaded) are called, if they require the ext_dl and the versions match * Callbacks of ext_dl are called if the required extensions are available * Did some testing with dl()