The only header file you really have to include for your modules is
php.h, located in the PHP directory. This file makes all
macros and API definitions required to build new modules available to your
code.
Tip: It's good practice to create a separate
header file for your module that contains module-specific
definitions. This header file should contain all the forward
definitions for exported functions and include
php.h. If you created your module using
ext_skel you already have such a header file
prepared.
To declare functions that are to be exported (i.e., made available to PHP
as new native functions), Zend provides a set of macros. A sample declaration
looks like this:
ZEND_FUNCTION ( my_function );
ZEND_FUNCTION declares a new C function that complies
with Zend's internal API. This means that the function is of
type void and
accepts INTERNAL_FUNCTION_PARAMETERS (another macro) as
parameters. Additionally, it prefixes the function name with
zif. The immediately expanded version of the above
definitions would look like this:
Expanding INTERNAL_FUNCTION_PARAMETERS
results in the following:
void zif_my_function( int ht
, zval * return_value
, zval * this_ptr
, int return_value_used
, zend_executor_globals * executor_globals
);
Since the interpreter and executor core have been separated from
the main PHP package, a second API defining macros and function
sets has evolved: the Zend API. As the Zend API now handles quite
a few of the responsibilities that previously belonged to PHP, a
lot of PHP functions have been reduced to macros aliasing to calls
into the Zend API. The recommended practice is to use the Zend API
wherever possible, as the old API is only preserved for
compatibility reasons. For example, the types zval
and pval are identical. zval is
Zend's definition; pval is PHP's definition
(actually, pval is an alias for zval
now). As the macro INTERNAL_FUNCTION_PARAMETERS
is a Zend macro, the above declaration contains
zval. When writing code, you should always use
zval to conform to the new Zend API.
The parameter list of this declaration is very important; you should keep these parameters in mind (see Табл. 46-1 for descriptions).
Таблица 46-1. Zend's Parameters to Functions Called from PHP
Parameter
Description
ht
The number of arguments passed to the Zend function.
You should not touch this directly, but instead use ZEND_NUM_ARGS() to obtain the
value.
return_value
This variable is used to pass any return values of
your function back to PHP. Access to this variable is best done using the
predefined macros. For a description of these see below.
this_ptr
Using this variable, you can gain access to the object
in which your function is contained, if it's used within an object. Use
the function getThis() to obtain this pointer.
return_value_used
This flag indicates whether an eventual return value
from this function will actually be used by the calling script.
0 indicates that the return value is not used;
1 indicates that the caller expects a return value.
Evaluation of this flag can be done to verify correct usage of the function as
well as speed optimizations in case returning a value requires expensive
operations (for an example, see how array.c makes use of
this).
executor_globals
This variable points to global settings of the Zend
engine. You'll find this useful when creating new variables, for example
(more about this later). The executor globals can also be introduced to your
function by using the macro TSRMLS_FETCH().
Now that you have declared the functions to be exported, you also
have to introduce them to Zend. Introducing the list of functions is done by
using an array of zend_function_entry. This array consecutively
contains all functions that are to be made available externally, with the function's name
as it should appear in PHP and its name as defined in the C source.
Internally, zend_function_entry is defined as shown in
Прим. 46-4.
Пример 46-4. Internal declaration of zend_function_entry.
Denotes the function name as seen in PHP (for
example, fopen, mysql_connect, or, in our
example, first_module).
handler
Pointer to the C function responsible for handling calls
to this function. For example, see the standard macro
INTERNAL_FUNCTION_PARAMETERS discussed earlier.
func_arg_types
Allows you to mark certain parameters so that they're forced
to be passed by reference. You usually should set this to
NULL.
In the example above, the declaration looks like this:
You can see that the last entry in the list always has to be
{NULL, NULL, NULL}.
This marker has to be set for Zend to know when the end of the
list of exported functions is reached.
Замечание:
You cannot use the predefined macros for the
end marker, as these would try to refer to a function named "NULL"!
The macro ZEND_FE (short for 'Zend Function
Entry') simply expands to a structure entry in
zend_function_entry. Note that these macros
introduce a special naming scheme to your functions - your C
functions will be prefixed with zif_, meaning
that ZEND_FE(first_module) will refer to a C
function zif_first_module(). If you want to mix
macro usage with hand-coded entries (not a good practice), keep
this in mind.
Tip: Compilation errors that refer to functions
named zif_*() relate to functions defined
with ZEND_FE.
Табл. 46-2 shows a list of all the macros
that you can use to define functions.
Таблица 46-2. Macros for Defining Functions
Macro Name
Description
ZEND_FE(name, arg_types)
Defines a function entry of the name name in
zend_function_entry. Requires a corresponding C
function. arg_types needs to be set to NULL.
This function uses automatic C function name generation by prefixing the PHP
function name with zif_.
For example, ZEND_FE("first_module", NULL) introduces a
function first_module() to PHP and links it to the C
function zif_first_module(). Use in conjunction
with ZEND_FUNCTION.
ZEND_NAMED_FE(php_name, name, arg_types)
Defines a function that will be available to PHP by the
name php_name and links it to the corresponding C
function name. arg_types needs to be set
to NULL. Use this function if you don't want the automatic
name prefixing introduced by ZEND_FE. Use in conjunction
with ZEND_NAMED_FUNCTION.
ZEND_FALIAS(name, alias, arg_types)
Defines an alias named alias for
name. arg_types needs to be set
to NULL. Doesn't require a corresponding C
function; refers to the alias target instead.
PHP_FE(name, arg_types)
Old PHP API equivalent of ZEND_FE.
PHP_NAMED_FE(runtime_name, name, arg_types)
Old PHP API equivalent of ZEND_NAMED_FE.
Note: You can't use
ZEND_FE in conjunction with
PHP_FUNCTION, or PHP_FE in
conjunction with ZEND_FUNCTION. However, it's
perfectly legal to mix ZEND_FE and
ZEND_FUNCTION with PHP_FE
and PHP_FUNCTION when staying with the same
macro set for each function to be declared. But mixing is
not recommended; instead, you're advised to
use the ZEND_* macros only.
This block is stored in the structure
zend_module_entry and contains all necessary
information to describe the contents of this module to Zend. You can
see the internal definition of this module in
Прим. 46-5.
Пример 46-5. Internal declaration of zend_module_entry.
typedef struct _zend_module_entry zend_module_entry;
struct _zend_module_entry {
unsigned short size;
unsigned int zend_api;
unsigned char zend_debug;
unsigned char zts;
char *name;
zend_function_entry *functions;
int (*module_startup_func)(INIT_FUNC_ARGS);
int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
int (*request_startup_func)(INIT_FUNC_ARGS);
int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);
void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
char *version;
[ Rest of the structure is not interesting here ]
};
Entry
Description
size, zend_api,
zend_debug and zts
Usually filled with the
"STANDARD_MODULE_HEADER", which fills these
four members with the size of the whole zend_module_entry, the
ZEND_MODULE_API_NO, whether it is a debug
build or normal build (ZEND_DEBUG) and if
ZTS is enabled (USING_ZTS).
name
Contains the module name (for example, "File
functions", "Socket functions",
"Crypt", etc.). This name will show up in
phpinfo(), in the section "Additional
Modules."
functions
Points to the Zend function block, discussed in the preceding
section.
module_startup_func
This function is called once upon module initialization and can
be used to do one-time initialization steps (such as initial
memory allocation, etc.). To indicate a failure during
initialization, return FAILURE; otherwise,
SUCCESS. To mark this field as unused, use
NULL. To declare a function, use the macro
ZEND_MINIT.
module_shutdown_func
This function is called once upon module shutdown and can be
used to do one-time deinitialization steps (such as memory
deallocation). This is the counterpart to
module_startup_func(). To indicate a failure
during deinitialization, return FAILURE;
otherwise, SUCCESS. To mark this field as
unused, use NULL. To declare a function, use
the macro ZEND_MSHUTDOWN.
request_startup_func
This function is called once upon every page request and can be
used to do one-time initialization steps that are required to
process a request. To indicate a failure here, return
FAILURE; otherwise,
SUCCESS. Note: As
dynamic loadable modules are loaded only on page requests, the
request startup function is called right after the module
startup function (both initialization events happen at the same
time). To mark this field as unused, use
NULL. To declare a function, use the macro
ZEND_RINIT.
request_shutdown_func
This function is called once after every page request and works
as counterpart to request_startup_func(). To
indicate a failure here, return FAILURE;
otherwise, SUCCESS.
Note: As dynamic loadable modules are
loaded only on page requests, the request shutdown function is
immediately followed by a call to the module shutdown handler
(both deinitialization events happen at the same time). To mark
this field as unused, use NULL. To declare a
function, use the macro ZEND_RSHUTDOWN.
info_func
When phpinfo() is called in a script, Zend
cycles through all loaded modules and calls this function.
Every module then has the chance to print its own "footprint"
into the output page. Generally this is used to dump
environmental or statistical information. To mark this field as
unused, use NULL. To declare a function, use
the macro ZEND_MINFO.
version
The version of the module. You can use
NO_VERSION_YET if you don't want to give the
module a version number yet, but we really recommend that you
add a version string here. Such a version string can look like
this (in chronological order): "2.5-dev",
"2.5RC1", "2.5" or
"2.5pl3".
Remaining structure elements
These are used internally and can be prefilled by using the
macro STANDARD_MODULE_PROPERTIES_EX. You
should not assign any values to them. Use
STANDARD_MODULE_PROPERTIES_EX only if you
use global startup and shutdown functions; otherwise, use
STANDARD_MODULE_PROPERTIES directly.
In our example, this structure is implemented as follows:
This is basically the easiest and most minimal set of values you
could ever use. The module name is set to First
Module, then the function list is referenced, after which
all startup and shutdown functions are marked as being unused.
For reference purposes, you can find a list of the macros involved
in declared startup and shutdown functions in
Табл. 46-3. These are
not used in our basic example yet, but will be demonstrated later
on. You should make use of these macros to declare your startup and
shutdown functions, as these require special arguments to be passed
(INIT_FUNC_ARGS and
SHUTDOWN_FUNC_ARGS), which are automatically
included into the function declaration when using the predefined
macros. If you declare your functions manually and the PHP
developers decide that a change in the argument list is necessary,
you'll have to change your module sources to remain compatible.
Таблица 46-3. Macros to Declare Startup and Shutdown Functions
Macro
Description
ZEND_MINIT(module)
Declares a function for module startup. The generated name will
be zend_minit_<module> (for example,
zend_minit_first_module). Use in
conjunction with ZEND_MINIT_FUNCTION.
ZEND_MSHUTDOWN(module)
Declares a function for module shutdown. The generated name
will be zend_mshutdown_<module> (for
example, zend_mshutdown_first_module). Use
in conjunction with ZEND_MSHUTDOWN_FUNCTION.
ZEND_RINIT(module)
Declares a function for request startup. The generated name
will be zend_rinit_<module> (for
example, zend_rinit_first_module). Use in
conjunction with ZEND_RINIT_FUNCTION.
ZEND_RSHUTDOWN(module)
Declares a function for request shutdown. The generated name
will be zend_rshutdown_<module> (for
example, zend_rshutdown_first_module). Use
in conjunction with ZEND_RSHUTDOWN_FUNCTION.
ZEND_MINFO(module)
Declares a function for printing module information, used when
phpinfo() is called. The generated name will
be zend_info_<module> (for example,
zend_info_first_module). Use in conjunction
with ZEND_MINFO_FUNCTION.
The function implementation is surrounded by a conditional
compilation statement. This is needed since the function
get_module() is only required if your module is
built as a dynamic extension. By specifying a definition of
COMPILE_DL_FIRSTMOD in the compiler command
(see above for a discussion of the compilation instructions
required to build a dynamic extension), you can instruct your
module whether you intend to build it as a dynamic extension or as
a built-in module. If you want a built-in module, the
implementation of get_module() is simply left
out.
get_module() is called by Zend at load time
of the module. You can think of it as being invoked by the
dl() call in your script. Its purpose is to pass the
module information block back to Zend in order to inform the engine about the
module contents.
If you don't implement a get_module() function in
your dynamic loadable module, Zend will compliment you with an error message
when trying to access it.
Implementing the exported functions is the final step. The
example function in first_module looks like this:
ZEND_FUNCTION(first_module)
{
long parameter;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", ¶meter) == FAILURE) {
return;
}
RETURN_LONG(parameter);
}
The function declaration is done
using ZEND_FUNCTION, which corresponds
to ZEND_FE in the function entry table (discussed
earlier).
After the declaration, code for checking and retrieving the function's
arguments, argument conversion, and return value generation follows (more on
this later).
That's it, basically - there's nothing more to implementing PHP modules.
Built-in modules are structured similarly to dynamic modules, so, equipped
with the information presented in the previous sections, you'll be able to
fight the odds when encountering PHP module source files.
Now, in the following sections, read on about how to make use of PHP's
internals to build powerful extensions.