[PHP4BETA] PHP 4 HOWTO

From: Date: Fri, 09 Apr 1999 00:55:20 +0000
Subject: [PHP4BETA] PHP 4 HOWTO
Groups: php.version4 
Request: Send a blank email to php-version4+get-31@lists.php.net to get a copy of this message
I'm going to try to list the important changes in API and programming techniques that are involved in developing modules for PHP4/Zend, as opposed to PHP3. Listing the whole PHP4 API is way beyond my scope here, it's mostly a 'diff' from the apidoc.txt, which you're all pretty familiar with. An important note that I neglected to mention yesterday - the php4 tree is based on the php 3.0.5 tree, plus all 3.0.6 patches hand-patched into it. Notably, it does NOT include any 3.0.7 patches. All of those have to be reapplied, with extreme care - modules should be safe to patch (mostly), but anything that touches the core or main.c will almost definitely require changes in order to work properly. [1] Symbol Tables One of the major changes in Zend involves changing the way symbols tables work. Zend enforces reference counting on all values and resources. This required changes in the semantics of the hash tables that implement symbol tables. Instead of storing pval in the hashes, we now store pval *. All of the API functions in Zend were changed in a way that this change is completely transparent. However, if you've used 'low level' hash functions to access or update elements in symbol tables, your code will require changes. Following are two simple examples, one demonstrates the difference between PHP3 and Zend when reading a symbol's value, and the other demonstrates the difference when writing a value. php3_read() { pval *foo; _php3_hash_find(ht, "foo", sizeof("foo"), &foo); /* foo->type is the type and foo->value is the value */ } php4_read() { pval **foo; _php3_hash_find(ht, "foo", sizeof("foo"), &foo); /* (*foo)->type is the type and (*foo)->value is the value */ } --- php3_write() { pval newval; newval.type = ...; newval.value = ...; _php3_hash_update(ht, "bar", sizeof("bar"), &newval, sizeof(pval), NULL); } php4_write() { pval *newval = (pval *) emalloc(sizeof(pval)); newval->refcount=1; newval->is_ref=0; newval->type = ...; newval->value = ...; _php3_hash_update(ht, "bar", sizeof("bar"), &newval, sizeof(pval *), NULL); } [2] Resources One of the 'cute' things about the reference counting support is that it completely eliminates the problem of resource leaking. A simple loop that included '$result = mysql_query(...)' in PHP leaked unless the user remembered to run mysql_free($result) at the end of the loop body, and nobody really did. In order to take advantage of the automatic resource deallocation upon destruction, there's virtually one small change you need to conduct. Change the result type of a resource that you want to destroy itself as soon as its no longer referenced (just about any resource I can think of) as IS_RESOURCE, instead of as IS_LONG. The rest is magic. A special treatment is required for SQL modules that follow MySQL's approach for having the link handle as an optional argument. Modules that follow the MySQL module model, store the last opened link in a global variable, that they use in case the user neglects to explicitly specify a link handle. Due to the way referenec counting works, this global reference is just like any other reference, and must increase that SQL link resource's reference count (otherwise, it will be closed prematurely). Simply, when you set the default link to a certain link, increase that link's reference count by calling zend_list_addref(). As always, the MySQL module is the one used to demonstrate 'new technology'. You can look around it and look for IS_RESOURCE, as well as zend_list_addref(), to see a clear example of how the new API should be used. [3] Thread safety issues I'm not going to say that Zend was designed with thread safety in mind, but from some point, we've decided upon several guidelines that would make the move to thread safety much, much easier. Generally, we've followed the PHP 3.1 approach of moving global variables to a structure, and encapsulating all global variable references within macros. There are three main differences: 1. We grouped related globals in a single structure, instead of grouping all globals in one structure. 2. We've used much, much shorter macro names to increase the readability of the source code. 3. Regardless of whether we're compiling in thread safe mode or not, all global variables are *always* stored in a structure. For example, you would never have a global variable 'foo', instead, it'll be a property of a global structure, for example, compiler_globals.foo. That makes development much, much easier, since your code will simply not compile unless you remember to put the necessary macro around foo. To write code that'll be thread safe in the future (when we release our thread safe memory manager and work on integrating it), you can take a look at zend_globals.h. Essentially, two sets of macros are defined, one for thread safe mode, and one for thread unsafe mode. All global references are encapsulated within ???G(varname), where ??? is the appropriate prefix for your structure (for example, so far we have CG(), EG() and AG(), which stand for the compiler, executor and memory allocator, respectively). When compiling with thread safety enabled, each function that makes use of a ???G() macro, must obtain the pointer to its copy of the structure. It can do so in one of two forms: 1. It can receive it as an argument. 2. It can fetch it. Obviously, the first method is preferable since it's much quicker. However, it's not always possible to send the structure all the way to a particular function, or it may simply bloat the code too much in some cases. Functions that receive the globals as an argument, should look like this: rettype functioname(???LS_D) <-- a function with no arguments rettype functioname(type arg1, ..., type argn ???LS_DC) <-- a funciton with arguments Calls to such functions should look like this: functionname(???LS_C) <-- a function with no arguments functionname(arg1, ..., argn ???LS_CC) <-- a function with arguments LS stands for 'Local Storage', _C stands for Call and _CC stands for Call Comma, _D stands for Declaration and _DC stands for Declaration Comma. Note that there's NO comma between the last argument and ???LS_DC or ???LS_CC. In general, every module that makes use of globals should use this approach if it plans to be thread safe. [4] Generalized INI support This is currently still under construction, so I'll keep you updated in the next few days. That's the important things I can think of right now. Happy coding! Zeev -- Zeev Suraski <zeev@zend.com> http://www.zend.com/ For a PGP public key, finger bourbon@netvision.net.il -- PHP 4 Beta

« previous php.version4 (#31) next »