Table of Contents

This page contains bits and pieces of the Zend Engine documentation:

Op-array structure

Objects

See here.

FAQ

These are questions, often times with answers, for the PHP Internals. This document is temporary until it's polished and finds a home within the PHP Manual sources. Feel free to add questions with or without answers.

Note: This is rough, feel free to clean it up.

C++

Extensions can be written in C++, you have to add PHP_REQUIRE_CXX to the config.m4 file to make the build system C++-aware though.

To allow static builds of the extension one has to mind this:

09:20:43 <johannes_> and ext/extname/php_extname.h has to be a valid C header, not C++, as it's included in internal_functions.c ...
09:22:06 <dsp_> hmm, that's the point..
09:23:01 <johannes_> you can have your own additional header for C++ suff, but that one has to be C compatible

Memory Management

[12:00pm] scoates: ok.. last question for now, I think: should I explicitly destroy on RSHUTDOWN, or let the non-persistent flag take care of that?
[12:00pm] johannes_: always cleanup yourself

Note here: while MM shutdown will take care of all allocated memory, it won't run any dtors etc., that's why it is important to clean up the resources properly - otherwise external dependencies can be messed up. And of course you'd get leaks reported in the debug mode.

Causes for crashes

Throwing Exceptions

If throwing exceptions results in a segmentation fault on 64bit systems only, then be sure that you have:

#include "zend_exceptions.h" 

(Remark: This header is always needed. The segfault might be caused by the fact, that C defaults the return value and parameters of undefined parameters to int. In cases where pointers and/or long data types are needed this might be wrong so a wrong function call is being made. A good compiler should give a warning. --johannes)

Hashes

[11:58am] scoates: what's the difference between zend_hash_[add] and zend_hash_quick_[add] ?
[11:58am] scoates: removal of gofaster loops? (-:
[11:58am] Derick: with the 2nd one you can provide an already calculated hash-list index
[11:59am] scoates: and the hashtable will automatically grow on _add, right? the length passed to init is just a hint?
[11:59am] johannes_: right

Unsorted

Add your random stuff here. I'll move it/update it/fix it (Derick)

How to get __LINE__ and __FILE__?

How do I detect the SAPI?

Extension Globals

To use extension globals (which are either true globals or thread local globals, depending on whether ZTS is enabled), follow these steps:

- In php_extname.h, declare which global variables you need with:

ZEND_BEGIN_MODULE_GLOBALS(extname)
	int	var1;
	char	*var2;
	....
ZEND_END_MODULE_GLOBALS(extname)

This will declare a structure (typedef'd to zend_extname_globals) that will hold all your globals.

- In php_extname.h, add

ZEND_EXTERN_MODULE_GLOBALS(extname);

. This will produce an allusion that will allow you to access the globals from every compile unit that includes php_extname.h In particular, this produces an allusion to an integer named extname_globals_id in ZTS builds or directly to a zend_extname_globals named extname_globals in non-ZTS builds.

- In php_extname.h, define a macro named EXTNAME_G, like this:

#ifdef ZTS
# define EXTNAME_G(v) TSRMG(extname_globals_id, zend_extname_globals *, v)
#else
# define EXTNAME_G(v) (extname_globals.v)
#endif

This will allow you to access the globals in a consistent manner in both ZTS and non-ZTS builds, like this:

EXTNAME_G(var1)

- Now that you have declared the type that aggregates the globals and the variable that holds the globals, you must define the globals. In extname.c, add

ZEND_DECLARE_MODULE_GLOBALS(extname);

This produces a tentative definition of extname_globals_id or extname_globals (depending on whether it's a ZTS or non-ZTS build).

- If you needn't do any startup operations on your variables, you would already have function extension globals in non-ZTS builds. Tipically, you will also want to initialize some extension globals (for instance, to allocate some memory for the var2 extension global above) -- this is done with globals constructors and destructors. To make it work in ZTS builds and allow such operations, add the following to your zend_module_entry:

zend_module_entry extname_module_entry = {
	...
	ZEND_MODULE_INFO_N(extname),
	PHP_EXTNAME_VERSION,
	ZEND_MODULE_GLOBALS(extname),
	ZEND_MODULE_GLOBALS_CTOR_N(extname), //may be NULL
	ZEND_MODULE_GLOBALS_DTOR_N(extname), //may be NULL
	...
}

Note: do not use ZEND_INIT_MODULE_GLOBALS/ts_allocate_id. If used a shared extension, they will provoke an attempt to call the destructor after the module has been unloaded! Also, for all that is holy, do NOT initialize globals on MINIT (EXTNAME_G(var_ptr) = NULL), that won't work correctly in ZTS as it won't initialize the value in all threads.

- Now define the constructor and destructor functions:

ZEND_MODULE_GLOBALS_CTOR_D(extname)
{
	extname_globals->arg2 = pemalloc(1024, 1);
}

ZEND_MODULE_GLOBALS_DTOR_D(extname)
{
	pefree(extname_globals->arg2, 1);
}

The globals constructor and destructor are NOT execute per-request, they are part of the module startup/shutdown. The globals can store data across requests. If you need to do per-request operations to the globals, use module-activate and module-deactivate callbacks.

Note: ZEND_MODULE_GLOBALS_CTOR_D will declare a function as receiving a zend_extname_globals*, not void* and zend_module_entry is supposed to contain a function pointer type that receives void*. I think this violates the C standard (the declarations are incompatible), but should however by safe since the arguments have the same size.