A collection of tips for writing PHP extensions

  • 2020-03-31 20:30:19
  • OfStack

The red part is my comment.
For more information see:

1. The common functions have been encapsulated, in the zen_api.h header file, you don't need to look at the internal details and waste time. (refer to appendix A for extension and Embedding PHP)
2. Running the test program in terminal, you can see the extended internal error output, which is especially important for solving the memory leak problem. (compile a debug lib)
3. Modify "CFLAGS = -g-o2" in Makefile during development, remove optimization options, and add -wall and -pedantic to facilitate debugging and display compilation warnings;
Zval_ptr_dtor (zval*) is not available if strval is not copied. Efree (void*) is used.
5. The $_SERVER['PWD'] in terminal has a value, but it cannot be obtained through zend_getenv() because it is meaningless or unreliable.
6. Call the "export function", using INTERNAL_FUNCTION_PARAM_PASSTHRU; Declared non-exported functions can use the parameters of the exported function through INTERNAL_FUNCTION_PARAM.
7. Note: RETURN_TYPE is best used in curly braces when selecting parts, loops, etc.
Or no semicolon, because: #define RETURN_BOOL(b) {RETVAL_BOOL(b); The return; }.
8. If the function's arguments are referenced and not scalar, destruct first to prevent memory leaks.
9. It is better to determine whether there is an exception in EG(exception) before throwing an exception, otherwise memory leak will be caused.
The zend_getenv function does not work when the Web server API is ISAPI (IIS).
11. Pass in a data pointer to zend_stack_push(). The actual copy is the data that the pointer points to.
ZEND_API int zend_stack_push(zend_stack *stack, void *element, int size);
ZEND_API int zend_stack_top(zend_stack *stack, void **element);
Where size == sizeof(*element);
Similarly, zend_hash is the same, comparing zend_hash_update with zend_hash_find.
12. Use add_assoc_zval(HashTable*, const char*, zval*) to store zval* instead of zval, therefore,
When storing parameters passed in by the user, make a copy of the new zval or something unexpected will happen.
13. Zval_dtor (zval*) releases the variable and its internal reference memory. Zval_ptr_dtor (zval**) first checks the refcount
Then decide whether to call zval_dtor(zval*), zval_copy_dtor(zval*) only performs a deep copy, that is, a copy only
Start internal reference memory instead of copying zval;

14. For example, use VC to compile the dynamic link library of win, and the code calls the zend function, such as zend_getenv, which is defined as:



Extern "C" {
Extern ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC);
}
This function needs to be introduced. If you want to use the ZEND_API, you need to cancel LIBZEND_EXPORTS (including the preprocessing definition in the VC "Settings") or use ZEND_DLIMPORT.
ZEND_DLIMPORT char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC);
The following is taken from: zend_config.w32.h
 
#ifdef LIBZEND_EXPORTS 
# define ZEND_API __declspec(dllexport) 
#else 
# define ZEND_API __declspec(dllimport) 
#endif 
#define ZEND_DLEXPORT __declspec(dllexport) 
#define ZEND_DLIMPORT __declspec(dllimport) 

Executor_globals_id also needs to declare the following:
ZEND_DLIMPORT int executor_globals_id;
(this is useful if you have to manually compile certain extensions, as I did when I compiled the sqlite3 extension.)

Related articles: