PHP: Source Discussion - Manual

downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

Accepting Arguments Troubleshooting

Last updated: Fri, 26 Jan 2007

view this page in

# Source Discussion

Now that you've got a safe build environment and you're able to include the modules into PHP files, it's time to discuss how everything works.

## Module Structure

All PHP modules follow a common structure:

- Header file inclusions (to include all required macros, API definitions, etc.)

- C declaration of exported functions (required to declare the Zend function block)

- Declaration of the Zend function block

- Declaration of the Zend module block

- Implementation of get_module()

- Implementation of all exported functions

## Header File Inclusions

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.

## Declaring Exported Functions

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:

    void zif_my_function ( INTERNAL_FUNCTION_PARAMETERS );

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()`.

## Declaration of the Zend Function Block

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`.

    typedef struct _zend_function_entry {
        char *fname;
        void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
        unsigned char *func_arg_types;
    } zend_function_entry;

Entry | Description
`fname` | 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:

    zend_function_entry firstmod_functions[] =
    {
        ZEND_FE(first_module, NULL)
        {NULL, NULL, NULL}
    };

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.

## Declaration of the Zend Module Block

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:

    zend_module_entry firstmod_module_entry =
    {
        STANDARD_MODULE_HEADER,
        "First Module",
        firstmod_functions,
        NULL, NULL, NULL, NULL, NULL,
        NO_VERSION_YET,
        STANDARD_MODULE_PROPERTIES,
    };

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`.

## Creation of get_module()

This function is special to all dynamic loadable modules. Take a look at the creation via the `ZEND_GET_MODULE` macro first:

    #if COMPILE_DL_FIRSTMOD
         ZEND_GET_MODULE(firstmod)
    #endif

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.

## Implementation of All Exported Functions

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", &parameter) == 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).

## Summary

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.

add a note User Contributed Notes
Source Discussion
There are no user contributed notes for this page.
Accepting Arguments Troubleshooting

Last updated: Fri, 26 Jan 2007
show source | credits | stats | sitemap | contact | advertising | mirror sites
Copyright © 2001-2007 The PHP Group
All rights reserved.
This mirror generously provided by: Yahoo! Inc.
Last updated: Sat Mar 10 10:36:09 2007 PST