Developers Guide - flaupretre/php-ext-gen GitHub Wiki
In order to get a working extension using php-ext-gen, you must :
- first, write a global file to describe your extension. You can use yaml or json to write it.
- then, you will write the code for every functions you define. Each function is defined in a separate file, containing both metadata and C code blocks. The function metadata describes arguments and the C code is the code to insert when generating the final function code. In order to keep a maximal portability, it is highly recommended to use a set of pre-defined macros and types. This provides an abstraction layer, which will allow your code to be more portable on different PHP engines.
- you can also create other files. See below for the list of files you can define. Among others, you can create a subdirectory named 'tests', containing phpt tests for your extension.
- Once you are done, it's time to test. If you didn't do it earlier, download the latest release from github (download a tgz distribution, NOT the source tree in tgz form). This contains a file named php-ext-gen.phk. This is the php-ext-gen software. cd into the directory where you created all your source files and run 'php [path]/php-ext-gen.phk build' where [path] is the location of the php-ext-gen.phk file. This should generate a subdirectory name 'gen'. The 'gen' contains the 'ready-to-compile' extension. cd to 'gen' and proceed as with any other PECL extension (phpize, ./configure, make/make test/make install...).
Depending on the syntax you choose for your extension's description, the file is named global.yml or global.json. The schema below describes the format of this file, which is required.
Items between '[]' are optional. Others are required.
The syntax used below is Yaml. The schema is exactly the same for json.
name: //str - Extension name
version; // str - Extension version
[flags]:
[minfo_displays_ini]: // bool - whether minfo displays ini entries
[ini]: // array of ini settings (prefixed with extension name)
<name>:
type: // str - {bool|int|float|string}
default: // str - Default value - Use 0/1 for bool
[access]: // str - Access restrictions - default: PHP_INI_ALL
[var]: // str - name in module globals - default: ini name
[modify]: // str - Modify callback (C function)
...
[extra_files]: // array of files to copy to dest dir
<filename>: // Relative path from source dir
[expand]: // bool - Run file through twig ? Default=false
...
[functions]: // array of function names.
- <name> // str
...
[constants]: // array of constants to define
<name>:
type: // str - {null|bool|int|float|string}
value: // str - Value. See below for syntax
[resources]: // Array of resource types
- <name> // str
Global code blocks are defined in the optional 'global.twig.c' file. This file contains code blocks to insert in the generated C code.
Blocks are defined using twig's syntax :
{% block <block-name> %}
...
{% endblock %}
More information on twig's block syntax is available here.
Here are the code blocks you can define :
- user_module_globals_data : inserted in the modules globals structure definition. This should define the global data your extension needs.
- user_module_globals_init : the code to initialize this data.
- user_module_globals_dtor : the code to free module globals data.
- user_minfo : code to execute when phpinfo() is run.
- user_rinit : code to execute during rinit.
- user_rshutdown : code to execute during rshutdown.
- user_minit : code to execute during module init, after the code to init module globals, register ini entries, and declare constants.
- user_mshutdown : code to execute during module shutdown.
These are the main blocks you can define. For a more detailed list, check the main.twig.c template file.
Each function is defined in its own file. This file contains the metadata and C code for the function.
The name of the file is 'func..twig.c'.
The format of the file is :
<metadata>
...
{% block xxx %}
...
{% endblock %}
{% block...
There is no special character to separate metadata from C code. The first '{%' string marks the beginning of the code blocks.
Format :
arguments: // array of call arguments
<arg-name>:
type: // str - one of the supported argument types.
[resource_type]: // If resource accepted, only valid resource type
[byref]: // bool - pass arg by ref ? Default: false
[optional]: // bool - Arg is optional
[default]: // str - If no default, a value of 0 or NULL is used
Syntax :
{% block <name> %}
...
{% endblock %}
These are optional C code blocks to insert in generated function body.
For details on the architecture of the function blocks, please look at the 'function.twig.c' template file.
Defined block names :
inserted before the function definition starts.
The most important. This code receives the arguments and returns the function results.
Inserted at the end of local declarations in the external (PHP) function.
inserted before argument parsing begins. Allows to compute context-dependant default values.
Inserted after argument parsing.
Inserted before calling internal function.
Inserted just after internal function returns.
inserted at the end of the external function, just before return.
Each resource type is defined in its own file. This file contains the metadata and C code for the resource type.
The name of the file is 'resource..twig.c'.
The format of the file is :
<metadata>
...
{% block xxx %}
...
{% endblock %}
{% block...
There is no special character to sparate metadata from C code. The first '{%' string marks the beginning of the code blocks.
Format :
[display_string]: // str - String to display in debug/var_dump output
The fields of the data structure. This will be inserted in the structure declaration.
The destructor code for the structure elements.
Two variables can be used in this code :
- A pointer to the resource to destroy, named 'ptr',
- and a boolean, named 'persistent', indicating if you must destroy temporary or persistent memory. This value can be passed directly to eg_allocate().
Note that this code must not destroy the structure, just its contents. This means that, if your structure does not contain pointers (if it contains only numbers, for instance), you don't have anything to free, and you won't define this code block.
You can define files to be copied from the source dir to the destination dir, optionally transformed using twig during the copy. This is the case for C code or definitions you cannot or don't want to include in code blocks. In such a case, you define an extra file in the global configuration, and write a '#include' statement in 'user.h' or 'user.c'.
An extra file can be a subdirectory, which will be recursively duplicated.
The default is to generate a 'basic' config.m4 file, which is sufficient if you don't have a dependency on external resources. If you need more autoconf stuff than defining an 'enable-' option, you must write your own 'config.m4' file. If provided, it will be copied automatically in the destination directory.
This is temporary. Providing a config.m4 file will remain supported, but alternative ways will be supported in future versions.
Optional. If the file exists, its content is inserted at the beginning of the main C file. The user.h file should contain definitions and inclusions of external header files.
Optional. If defined, the content of this file is inserted before any other function code. It can define functions or #include extra files.
Note that, to keep thread safety, you should probably not define any global data outside of the module globals structure. The only exception is data that is never written outside of minit/mshutdown, and that must be shared (read-only) by every threads.