diff options
author | Zeev Suraski <zeev@php.net> | 1999-04-24 16:57:46 +0000 |
---|---|---|
committer | Zeev Suraski <zeev@php.net> | 1999-04-24 16:57:46 +0000 |
commit | 1ab3e00bc06fbe26c4d05533b9ffa61c36b15258 (patch) | |
tree | 4429dd84372f0663f021ab9f94fc57c70182d13c /apidoc-zend.txt | |
parent | f6971f17a96643e6f1a7640a3f282793b758ce37 (diff) | |
download | php-git-1ab3e00bc06fbe26c4d05533b9ffa61c36b15258.tar.gz |
Add my API letters to the CVS
Diffstat (limited to 'apidoc-zend.txt')
-rw-r--r-- | apidoc-zend.txt | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/apidoc-zend.txt b/apidoc-zend.txt new file mode 100644 index 0000000000..6472729f04 --- /dev/null +++ b/apidoc-zend.txt @@ -0,0 +1,276 @@ +Following is a merge of two letters I sent to php4beta@lists.php.net, +describing the changes in API between PHP 3.0 and PHP 4.0 (Zend). +This file is by no means thorough documentation of the PHP API, +and is intended for developers who are familiar with the PHP 3.0 API, +and want to port their code to PHP 4.0, or take advantage of its new +features. For highlights about the PHP 3.0 API, consult apidoc.txt. + +Zeev + +-------------------------------------------------------------------------- + +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 + +The code comes to solve several issues: + +a. The ugly long block of code in main.c that reads values from the +cfg_hash into php3_ini. +b. Get rid of php3_ini. The performance penalty of copying it around all +the time in the Apache module probably wasn't too high, but +psychologically, it annoyed me :) +c. Get rid of the ugly code in mod_php3.c, that also reads values from +Apache directives and puts them into the php3_ini structure. +d. Generalize all the code so that you only have to add an entry in one +single place and get it automatically supported in php3.ini, Apache, Win32 +registry, runtime function ini_get() and ini_alter() and any future method +we might have. +e. Allow users to easily override *ANY* php3.ini value, except for ones +they're not supposed to, of course. + +I'm happy to say that I think I pretty much reached all goals. php_ini.c +implements a mechanism that lets you add your INI entry in a single place, +with a default value in case there's no php3.ini value. What you get by +using this mechanism: + +1. Automatic initialization from php3.ini if available, or from the +default value if not. +2. Automatic support in ini_alter(). That means a user can change the +value for this INI entry at runtime, without you having to add in a single +line of code, and definitely no additional function (for example, in PHP3, +we had to add in special dedicated functions, like +set_magic_quotes_runtime() or the likes - no need for that anymore). +3. Automatic support in Apache .conf files. +4. No need for a global php3_ini-like variable that'll store all that +info. You can directly access each INI entry by name, in runtime. 'Sure, +that's not revolutionary, it's just slow' is probably what some of you +think - which is true, but, you can also register a callback function that +is called each time your INI entry is changed, if you wish to store it in a +cached location for intensive use. +5. Ability to access the current active value for a given INI entry, and +the 'master' value. + +Of course, (2) and (3) are only applicable in some cases. Some entries +shouldn't be overriden by users in runtime or through Apache .conf files - +you can, of course, mark them as such. + + +So, enough hype, how does it work. + +Essentially: + +static PHP_INI_MH(OnChangeBar); /* declare a message handler for a change +in "bar" */ + +PHP_INI_BEGIN() + PHP_INI_ENTRY("foo", "1", PHP_INI_ALL, NULL, NULL) + PHP_INI_ENTRY("bar", "bah", PHP_INI_SYSTEM, OnChangeBar, NULL) +PHP_INI_END() + +static PHP_INI_MH(OnChangeBar) +{ + a_global_var_for_bar = new_value; + return SUCCESS; +} + +int whatever_minit(INIT_FUNC_ARGS) +{ + ... + REGISTER_INI_ENTRIES(); + ... +} + + +int whatever_mshutdown(SHUTDOWN_FUNC_ARGS) +{ + ... + UNREGISTER_INI_ENTRIES(); + ... +} + + +and that's it. Here's what it does. As you can probably guess, this code +registers two INI entries - "foo" and "bar". They're given defaults "1" +and "bah" respectively - note that all defaults are always given as +strings. That doesn't reduce your ability to use integer values, simply +specify them as strings. "foo" is marked so that it can be changed by +anyone at any time (PHP_INI_ALL), whereas "foo" is marked so it can be +changed only at startup in the php3.ini only, presumably, by the system +administrator (PHP_INI_SYSTEM). +When "foo" changes, no function is called. Access to it is done using the +macros INI_INT("foo"), INI_FLT("foo") or INI_STR("foo"), which return a +long, double or char * respectively (strings that are returned aren't +duplicated - if they're manipulated, you must duplicate them first). You +can also access the original value (the 'master' value, in case one of them +was overriden by a user) using another pair of macros: +INI_ORIG_INT("foo"), INI_ORIG_FLT("foo") and INI_ORIG_STR("foo"). + +When "bar" changes, a special message handler is called, OnBarChange(). +Always declare those message handlers using PHP_INI_MH(), as they might +change in the future. Message handlers are called as soon as an ini entry +initializes or changes, and allow you to cache a certain INI value in a +quick C structure. In this example, whenever "bar" changes, the new value +is stored in a_global_var_for_bar, which is a global char * pointer, +quickly accessible from other functions. Things get a bit more complicated +when you want to implement a thread-safe module, but it's doable as well. +Message handlers may return SUCCESS to acknowledge the new value, or +FAILURE to reject it. That enables you to reject invalid values for some +INI entries if you want. Finally, you can have a pointer passed to your +message handler - that's the fifth argument to PHP_INI_ENTRY(). It is +passed as mh_arg to the message handler. + +Remember that for certain values, there's really no reason to mess with a +callback function. A perfect example for this are the syntax highlight +colors, which no longer have a dedicated global C slot that stores them, +but instead, are fetched from the php_ini hash on demand. + +"As always", for a perfect working example of this mechanism, consult +functions/mysql.c. This module uses the new INI entry mechanism, and was +also converted to be thread safe in general, and in its php_ini support in +particular. Converting your modules to look like this for thread safety +isn't a bad idea (not necessarily now, but in the long run). + |