All functions look like this:
void php3_foo(INTERNAL_FUNCTION_PARAMETERS) { } |
Arguments are always of type pval. This type
contains a union which has the actual type of the
argument. So, if your function takes two arguments, you
would do something like the following at the top of your
function:
When you change any of the passed parameters,
whether they are sent by reference or by value, you can
either start over with the parameter by calling
pval_destructor on it, or if it's an ARRAY you want to
add to, you can use functions similar to the ones in
internal_functions.h which manipulate return_value as an
ARRAY.
Also if you change a parameter to IS_STRING make
sure you first assign the new estrdup()'ed string and the
string length, and only later change the type to
IS_STRING. If you change the string of a parameter which
already IS_STRING or IS_ARRAY you should run
pval_destructor on it first.
A function can take a variable number of arguments.
If your function can take either 2 or 3 arguments, use
the following:
The type of each argument is stored in the pval type
field. This type can be any of the following:
表格 E-1. PHP Internal Types
If you get an argument of one type and would like to
use it as another, or if you just want to force the
argument to be of a certain type, you can use one of the
following conversion functions:
convert_to_long(arg1); convert_to_double(arg1); convert_to_string(arg1); convert_to_boolean_long(arg1); /* If the string is "" or "0" it becomes 0, 1 otherwise */ convert_string_to_number(arg1); /* Converts string to either LONG or DOUBLE depending on string */ |
These function all do in-place conversion. They do
not return anything.
The actual argument is stored in a union; the
members are:
IS_STRING: arg1- value.str.val
IS_LONG: arg1- value.lval
IS_DOUBLE: arg1- value.dval
Any memory needed by a function should be allocated
with either emalloc() or estrdup(). These are memory
handling abstraction functions that look and smell like
the normal malloc() and strdup() functions. Memory should
be freed with efree().
There are two kinds of memory in this program:
memory which is returned to the parser in a variable, and
memory which you need for temporary storage in your
internal function. When you assign a string to a variable
which is returned to the parser you need to make sure you
first allocate the memory with either emalloc() or
estrdup(). This memory should NEVER be freed by you,
unless you later in the same function overwrite your
original assignment (this kind of programming practice is
not good though).
For any temporary/permanent memory you need in your
functions/library you should use the three emalloc(),
estrdup(), and efree() functions. They behave EXACTLY
like their counterpart functions. Anything you emalloc()
or estrdup() you have to efree() at some point or
another, unless it's supposed to stick around until the
end of the program; otherwise, there will be a memory
leak. The meaning of "the functions behave exactly like
their counterparts" is: if you efree() something which
was not emalloc()'ed nor estrdup()'ed you might get a
segmentation fault. So please take care and free all of
your wasted memory.
If you compile with "-DDEBUG", PHP will print out a
list of all memory that was allocated using emalloc() and
estrdup() but never freed with efree() when it is done
running the specified script.
A number of macros are available which make it
easier to set a variable in the symbol table:
SET_VAR_STRING(name,value)
SET_VAR_DOUBLE(name,value)
SET_VAR_LONG(name,value)
|
Symbol tables in PHP are implemented as hash tables.
At any given time, symbol_table is a pointer to the
'main' symbol table, and active_symbol_table points to
the currently active symbol table (these may be identical
like in startup, or different, if you're inside a
function).
The following examples use 'active_symbol_table'.
You should replace it with symbol_table if you
specifically want to work with the 'main' symbol table.
Also, the same functions may be applied to arrays, as
explained below.
If you want to define a new array in a symbol table,
you should do the following.
First, you may want to check whether it exists and
abort appropriately, using hash_exists() or
hash_find().
Next, initialize the array:
Here's how to add new entries to it:
hash_next_index_insert() uses more or less the same
logic as "$foo[] = bar;" in PHP 2.0.
If you are building an array to return from a
function, you can initialize the array just like above by
doing:
if (array_init(return_value) == FAILURE) { failed...; } |
...and then adding values with the helper
functions:
add_next_index_long(return_value,long_value); add_next_index_double(return_value,double_value); add_next_index_string(return_value,estrdup(string_value)); |
Of course, if the adding isn't done right after the
array initialization, you'd probably have to look for the
array first:
pval *arr; if (hash_find(active_symbol_table,"foo",sizeof("foo"),(void **) arr)==FAILURE) { can't find... } else { use arr- value.ht... } |
Note that hash_find receives a pointer to a pval
pointer, and not a pval pointer.
Just about any hash function returns SUCCESS or
FAILURE (except for hash_exists(), which returns a
boolean truth value).
A number of macros are available to make returning
values from a function easier.
The RETURN_* macros all set the return value and
return from the function:
RETURN
RETURN_FALSE
RETURN_TRUE
RETURN_LONG(l)
RETURN_STRING(s,dup) If dup is TRUE, duplicates the
string
RETURN_STRINGL(s,l,dup) Return string (s)
specifying length (l).
RETURN_DOUBLE(d)
The RETVAL_* macros set the return value, but do not
return.
RETVAL_FALSE
RETVAL_TRUE
RETVAL_LONG(l)
RETVAL_STRING(s,dup) If dup is TRUE, duplicates the
string
RETVAL_STRINGL(s,l,dup) Return string (s)
specifying length (l).
RETVAL_DOUBLE(d)
The string macros above will all estrdup() the
passed 's' argument, so you can safely free the argument
after calling the macro, or alternatively use statically
allocated memory.
If your function returns boolean success/error
responses, always use RETURN_TRUE and RETURN_FALSE
respectively.
Your function can also return a complex data type
such as an object or an array.
Returning an object:
Call object_init(return_value).
Fill it up with values. The functions available
for this purpose are listed below.
Possibly, register functions for this object. In
order to obtain values from the object, the function
would have to fetch "this" from the
active_symbol_table. Its type should be IS_OBJECT,
and it's basically a regular hash table (i.e., you
can use regular hash functions on .value.ht). The
actual registration of the function can be done
using:
add_method( return_value, function_name, function_ptr ); |
The functions used to populate an object are:
add_property_long( return_value, property_name, l
) - Add a property named 'property_name', of type
long, equal to 'l'
add_property_double( return_value, property_name,
d ) - Same, only adds a double
add_property_string( return_value, property_name,
str ) - Same, only adds a string
add_property_stringl( return_value, property_name,
str, l ) - Same, only adds a string of length 'l'
Returning an array:
Call array_init(return_value).
Fill it up with values. The functions available
for this purpose are listed below.
The functions used to populate an array are:
add_assoc_long(return_value,key,l) - add
associative entry with key 'key' and long value
'l'
add_assoc_double(return_value,key,d)
add_assoc_string(return_value,key,str,duplicate)
add_assoc_stringl(return_value,key,str,length,duplicate)
specify the string length
add_index_long(return_value,index,l) - add entry
in index 'index' with long value 'l'
add_index_double(return_value,index,d)
add_index_string(return_value,index,str)
add_index_stringl(return_value,index,str,length) -
specify the string length
add_next_index_long(return_value,l) - add an array
entry in the next free offset with long value 'l'
add_next_index_double(return_value,d)
add_next_index_string(return_value,str)
add_next_index_stringl(return_value,str,length) -
specify the string length
PHP has a standard way of dealing with various types
of resources. This replaces all of the local linked lists
in PHP 2.0.
Available functions:
php3_list_insert(ptr, type) - returns the 'id' of
the newly inserted resource
php3_list_delete(id) - delete the resource with
the specified id
php3_list_find(id,*type) - returns the pointer of
the resource with the specified id, updates 'type' to
the resource's type
Typical list code would look like this:
|
PHP has a standard way of storing persistent
resources (i.e., resources that are kept in between
hits). The first module to use this feature was the MySQL
module, and mSQL followed it, so one can get the general
impression of how a persistent resource should be used by
reading mysql.c. The functions you should look at
are:
The general idea of persistence modules is this:
Code all of your module to work with the regular
resource list mentioned in section (9).
Code extra connect functions that check if the
resource already exists in the persistent resource
list. If it does, register it as in the regular
resource list as a pointer to the persistent resource
list (because of 1., the rest of the code should work
immediately). If it doesn't, then create it, add it
to the persistent resource list AND add a pointer to
it from the regular resource list, so all of the code
would work since it's in the regular resource list,
but on the next connect, the resource would be found
in the persistent resource list and be used without
having to recreate it. You should register these
resources with a different type (e.g. LE_MYSQL_LINK
for non-persistent link and LE_MYSQL_PLINK for a
persistent link).
If you read mysql.c, you'll notice that except for
the more complex connect function, nothing in the rest of
the module has to be changed.
The very same interface exists for the regular
resource list and the persistent resource list, only
'list' is replaced with 'plist':
php3_plist_insert(ptr, type) - returns the 'id' of
the newly inserted resource
php3_plist_delete(id) - delete the resource with
the specified id
php3_plist_find(id,*type) - returns the pointer of
the resource with the specified id, updates 'type' to
the resource's type
However, it's more than likely that these functions
would prove to be useless for you when trying to
implement a persistent module. Typically, one would want
to use the fact that the persistent resource list is
really a hash table. For instance, in the MySQL/mSQL
modules, when there's a pconnect() call (persistent
connect), the function builds a string out of the
host/user/passwd that were passed to the function, and
hashes the SQL link with this string as a key. The next
time someone calls a pconnect() with the same
host/user/passwd, the same key would be generated, and
the function would find the SQL link in the persistent
list.
Until further documented, you should look at mysql.c
or msql.c to see how one should use the plist's hash
table abilities.
One important thing to note: resources going into
the persistent resource list must *NOT* be allocated with
PHP's memory manager, i.e., they should NOT be created
with emalloc(), estrdup(), etc. Rather, one should use
the regular malloc(), strdup(), etc. The reason for this
is simple - at the end of the request (end of the hit),
every memory chunk that was allocated using PHP's memory
manager is deleted. Since the persistent list isn't
supposed to be erased at the end of a request, one
mustn't use PHP's memory manager for allocating resources
that go to it.
When you register a resource that's going to be in
the persistent list, you should add destructors to it
both in the non-persistent list and in the persistent
list. The destructor in the non-persistent list
destructor shouldn't do anything. The one in the
persistent list destructor should properly free any
resources obtained by that type (e.g. memory, SQL links,
etc). Just like with the non-persistent resources, you
*MUST* add destructors for every resource, even it
requires no destruction and the destructor would be
empty. Remember, since emalloc() and friends aren't to be
used in conjunction with the persistent list, you mustn't
use efree() here either.
Many of the features of PHP can be configured at
runtime. These configuration directives can appear in
either the designated php3.ini file, or in the case of
the Apache module version in the Apache .conf files. The
advantage of having them in the Apache .conf files is
that they can be configured on a per-directory basis.
This means that one directory may have a certain
safemodeexecdir for example, while another directory may
have another. This configuration granularity is
especially handy when a server supports multiple virtual
hosts.
The steps required to add a new directive:
Add directive to php3_ini_structure struct in
mod_php3.h.
In main.c, edit the php3_module_startup function
and add the appropriate cfg_get_string() or
cfg_get_long() call.
Add the directive, restrictions and a comment to
the php3_commands structure in mod_php3.c. Note the
restrictions part. RSRC_CONF are directives that can
only be present in the actual Apache .conf files. Any
OR_OPTIONS directives can be present anywhere,
include normal .htaccess files.
In either php3take1handler() or php3flaghandler()
add the appropriate entry for your directive.
In the configuration section of the _php3_info()
function in functions/info.c you need to add your new
directive.
And last, you of course have to use your new
directive somewhere. It will be addressable as
php3_ini.directive.