Skip to main content

php_module

Attribute Macro php_module 

Source
#[php_module]
Expand description

§#[php_module] Attribute

The module macro is used to annotate the get_module function, which is used by the PHP interpreter to retrieve information about your extension, including the name, version, functions and extra initialization functions. Regardless if you use this macro, your extension requires a extern "C" fn get_module() so that PHP can get this information.

The function is renamed to get_module if you have used another name. The macro also exports a crate-prefixed <crate_name>_get_module alias, used when statically linking the extension into php-src. Building with EXT_PHP_RS_STATIC_EXT=1 removes the unmangled get_module export (the function itself stays callable from Rust) so a statically linked extension cannot collide with another extension exporting get_module. Dynamic builds (extension= / dl()) must not set the variable.

The function is passed an instance of ModuleBuilder which allows you to register the following (if required):

  • Functions, classes, and constants
  • Extension and request startup and shutdown functions.
    • Read more about the PHP extension lifecycle here.
  • PHP extension information function
    • Used by the phpinfo() function to get information about your extension.

Classes and constants are not registered with PHP in the get_module function. These are registered inside the extension startup function.

§Startup failures

If a constant, an interface, a class or an enum cannot be registered, the generated startup function logs the cause as an E_CORE_WARNING and returns FAILURE. PHP then reports Unable to start <extension> module. At engine startup PHP exits. From dl() the request fails. A panic during registration gets the same treatment. The process does not abort in either case.

get_module cannot report a failure, because PHP reads the returned entry without a check. If the ModuleBuilder cannot become a module entry, for example because a function name, an argument name or the module name contains a NUL byte, the macro returns a placeholder entry with the name of the crate. The startup function of that entry logs the build error and fails as described above.

The startup function that you name in #[php(startup = ...)] is your own extern "C" function. A panic inside it is not caught.

You can also give a startup function to ModuleBuilder::startup_function. The generated startup function calls it after the #[php(startup = ...)] function. The two functions run before the macro registers the constants, interfaces, classes and enums.

§Usage

ⓘ
use ext_php_rs::{
    prelude::*,
    zend::ModuleEntry,
    info_table_start,
    info_table_row,
    info_table_end
};

#[php_const]
pub const MY_CUSTOM_CONST: &'static str = "Hello, world!";

#[php_class]
pub struct Test {
    a: i32,
    b: i32
}
#[php_function]
pub fn hello_world() -> &'static str {
    "Hello, world!"
}

/// Used by the `phpinfo()` function and when you run `php -i`.
/// This will probably be simplified with another macro eventually!
pub extern "C" fn php_module_info(_module: *mut ModuleEntry) {
    info_table_start!();
    info_table_row!("my extension", "enabled");
    info_table_end!();
}

#[php_module]
pub fn get_module(module: ModuleBuilder) -> ModuleBuilder {
    module
        .constant(wrap_constant!(MY_CUSTOM_CONST))
        .class::<Test>()
        .function(wrap_function!(hello_world))
        .info_function(php_module_info)
}