The examples provided in this section serve as a starting point for building or laying out larger extensions. By filling in your own code in the noted places, you can focus on the functional bits rather than worrying about formatting and other boring make-work.
All templates provided hereunless otherwise notedare neutrally named cookbook and should be changed to a more appropriate name when you implement them. In all instances, assume casing to be significantfor example, cookbook is not the same as COOKBOOK.
Note
The material covered in this section is just a consolidated rehash of the core material covered in the body of this book. If you already feel familiar with it, skip down to the Code Pantry later in this appendix.
Minimal Extension
If you've been through more than a little of the book, this framework will look instantly familiar. It's the first extension you saw in Chapter 5, aptly named "Your First Extension."
The three files shown in Listings C.1, C.2, and C.3 represent the absolute least amount of code and configuration data necessary to build a loadable PHP extension. Refer back to Chapter 5 for a refresher on how to build this as a loadable module.
Listing C.1. config.m4A Simple Configuration Script
PHP_ARG_ENABLE(cookbook, [Whether to enable the "cookbook" extension], [ enable-cookbook Enable "cookbook" extension support]) if test $PHP_COOKBOOK != "no"; then PHP_SUBST(COOKBOOK_SHARED_LIBADD) PHP_NEW_EXTENSION(cookbook, cookbook.c, $ext_shared) fi |
Listing C.2. php_cookbook.hA Simple Header File
#ifndef PHP_COOKBOOK_H #define PHP_COOKBOOK_H #define PHP_COOKBOOK_EXTNAME "cookbook" /* The value of this constant may be arbitrarily chosen by you. PHP does not actually use this value internally; however it makes sense to incrementally increase it with each release. */ #define PHP_COOKBOOK_EXTVER "1.0" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" extern zend_module_entry cookbook_module_entry; #define phpext_cookbook_ptr &cookbook_module_entry #endif |
Listing C.3. cookbook.cA Simple Extension Source File
#include "php_cookbook.h" zend_module_entry cookbook_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_COOKBOOK_EXTNAME, NULL, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */ #if ZEND_MODULE_API_NO >= 20010901 PHP_COOKBOOK_EXTVER, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_COOKBOOK ZEND_GET_MODULE(cookbook) #endif |
Extension Life Cycle Methods
Chapter 1, "The PHP Life Cycle," and many of the following chapters discussed the five phases engaged by PHP during the course of its execution: Startup, Activation, Runtime, Deactivation, and Shutdown.
During all but the Runtime phase, PHP activates an appropriate callback found in the zend_module_entry structure. Each of these methods can be left NULL and unused as in the minimal skeleton shown previously, or implemented independently using the appropriate naming and prototype macros. Under ordinary circumstances each method should return the SUCCESS constant. If a callback is unable to perform a vital task, it must return FAILURE so that PHP can raise the proper error and exit if necessary.
Add any or all of these functions as needed to any of the source files in your projectproviding they are visible to your zend_module_entry structure. Listing C.4 shows a set of minimal implementations for these callbacks.
Listing C.4. Declaring Life Cycle Callbacks
PHP_MINIT_FUNCTION(cookbook) { /* Code placed here will be executed during the Startup phase Startup occurs when the PHP interpreter is first being initialized prior to entering any Activation phases The M in MINIT is for "Module" (a.k.a. Extension) Initialization */ return SUCCESS; } PHP_RINIT_FUNCTION(cookbook) { /* Code placed here will be executed during the Activation phase(s) Activation occurs just prior to the execution of each script request. The R in RINIT is for "Request" Initialization */ return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(cookbook) { /* Code placed here will be executed during the Deactivation phase(s) Deactivation occurs just after completion of a given script request. */ return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(cookbook) { /* Code placed here will be executed during the Shutdown phase Shutdown occurs after all requests have been processed and the SAPI is proceeding to unload. */ return SUCCESS; } |
For each callback function added, replace the corresponding NULL entry (denoted by comments in Listing C.3) with the matching use macro (see Listing C.5).
Listing C.5. Adding Callback Macros to zend_module_entry
zend_module_entry cookbook_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_COOKBOOK_EXTNAME, NULL, /* Functions */ PHP_MINIT(cookbook), /* MINIT */ PHP_MSHUTDOWN(cookbook), /* MSHUTDOWN */ PHP_RINIT(cookbook), /* RINIT */ PHP_RSHUTDOWN(cookbook), /* RSHUTDOWN */ NULL, /* MINFO */ #if ZEND_MODULE_API_NO >= 20010901 PHP_COOKBOOK_EXTVER, #endif STANDARD_MODULE_PROPERTIES }; |
Declaring Module Info
To add extension-specific information to output generated by phpinfo();, add an MINFO callback function to your source file and place a matching macro into your zend_module_entry structure (see Listing C.6). Unlike the life cycle functions, the MINFO callback does not expect a return value.
Listing C.6. Declaring Module Information
PHP_MINFO_FUNCTION(cookbook) { /* The following example will display a simple 2x2 table Refer to Chapter 12, "Startup, Shutdown, and a Few Points in Between" For more information on generating MINFO output */ php_info_print_table_start(); php_info_print_table_row(2, "Cookbook Module", "enabled"); php_info_print_table_row(2, "version", PHP_COOKBOOK_EXTVER); php_info_print_table_end(); } |
As with the life cycle callbacks, replace the NULL entry in your zend_module_entry structure corresponding to MINFO with: PHP_MINFO(cookbook).
Adding Functions
Internal implementations of userspace functions are declared to the engine using a vector of zend_function_entry structures as described in Chapter 5, "Your First Extension." Place the structure shown in Listing C.7 just above your zend_module_entry struct.
Listing C.7. Empty Function Entry List
zend_function_entry php_cookbook_functions[] = { /* Function entry macros such as PHP_FE(), PHP_FALIAS, and PHP_NAMED_FE() go here */ { NULL, NULL, NULL } }; |
Now link that new structure into your module entry by replacing the NULL corresponding to the functions list with php_cookbook_functions.
After the zend_function_entry structure is in place, define actual function implementations using PHP_FUNCTION() macros such as shown in Listing C.8.
Listing C.8. Empty Function Declaration
PHP_FUNCTION(cookbook_dosomething) { /* Code to be executed when cookbook_dosomething() is called from userspace goes here */ } |
Now place a matching entry into your zend_function_entry structure prior to the terminating NULL entry: PHP_FE(cookbook_dosomething, NULL).
Adding Resources
PHP uses the resource data type to store opaque or complex data types that don't or can't map to PHP userspace data (see Listing C.9). These types are declared in the MINIT callback of an extension, which is called during the Startup phase. Refer to Chapter 9, "The Resource Data Type," for a detailed explanation of their use.
Listing C.9. Declaring a Resource Type
/* List Entry type IDs are registered in a common pool shared by all threads And therefore can be stored in a true-global scope */ int le_cookbook_type; /* The name of your resource type may be arbitrarily assigned and does not necessarily have to be unique, although good practices dictate it should be. */ #define PHP_COOKBOOK_RESOURCE_NAME "Cookbook Resource" /* Don't forget: Since MINIT is being used, it must be referenced from the zend_module_entry structure */ PHP_MINIT_FUNCTION(cookbook) { le_cookbook_type = zend_register_list_destructors_ex( NULL, /* Non-persistent destructor */ NULL, /* Persistent destructor */ PHP_COOKBOOK_RESOURCE_NAME, module_number); return SUCCESS; } |
When a resource variable is implicitly freed during the Deactivation phase or during the course of a request because it has been unset() or has fallen out of scope, its nonpersistent destructor is called. For persistent resources, explained in Chapter 9, the persistent destructor will also be called when the resource is removed from the persistent list, typically in response to an explicit close or shut down command.
The prototypes for both destructors are identical (see Listing C.10):
Listing C.10. Resource Destructor Callbacks
void php_cookbook_resource_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) { /* The registered data to be destructed can be found in rsrc->ptr */ } |
Once defined, the name of the destructor callback (php_cookbook_resource_dtor) can be added to the zend_register_list_destructors_ex() call in place of either or both of the NULL placeholders as appropriate.
Adding Objects
The simplest useful object declaration begins with a few lines in the MINIT callback and a declaration of at least one method (see Listing C.11).
Listing C.11. Adding Objects
PHP_METHOD(Cookbook_Class,__construct) { /* Code added here will be executed in response to calling Cookbook_Class::__construct(), including in response to new Cookbook_Class() which implicitly calls the constructor */ } zend_function_entry php_cookbook_methods[] = { /* Refer to Chapter 11, "PHP5 Objects," for the meaning of the ZEND_ACC_* constants */ PHP_ME(Cookbook_Class,__construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) { NULL, NULL, NULL } }; /* Don't forget: Because MINIT is being used, it must be referenced from the zend_module_entry structure */ PHP_MINIT_FUNCITON(cookbook) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "Cookbook_Class", php_cookbook_methods); zend_register_internal_class(&ce TSRMLS_CC); return SUCCESS; } |
Code Pantry |
The PHP Life Cycle
Variables from the Inside Out
Memory Management
Setting Up a Build Environment
Your First Extension
Returning Values
Accepting Parameters
Working with Arrays and HashTables
The Resource Data Type
PHP4 Objects
PHP5 Objects
Startup, Shutdown, and a Few Points in Between
INI Settings
Accessing Streams
Implementing Streams
Diverting the Stream
Configuration and Linking
Extension Generators
Setting Up a Host Environment
Advanced Embedding
Appendix A. A Zend API Reference
Appendix B. PHPAPI
Appendix C. Extending and Embedding Cookbook
Appendix D. Additional Resources