CVS update: php3/doc/appendices
| From: | cslawi | Date: | Tue, 08 Sep 1998 10:33:34 +0000 |
| Subject: | CVS update: php3/doc/appendices | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-873@lists.php.net to get a copy of this message | ||
Date: Tuesday September 8, 1998 @ 6:33
Author: cslawi
Update of /repository/php3/doc/appendices
In directory asf:/u2/tmp/cvs-serv26916
Modified Files:
phpdevel.sgml
Log Message:
Pulled in 'Adding functions to PHP3' from apidoc.txt.
Most formatting done; still needs some work.
Index: php3/doc/appendices/phpdevel.sgml
diff -c php3/doc/appendices/phpdevel.sgml:1.12 php3/doc/appendices/phpdevel.sgml:1.13
*** php3/doc/appendices/phpdevel.sgml:1.12 Sun Jul 26 18:07:21 1998
--- php3/doc/appendices/phpdevel.sgml Tue Sep 8 06:33:33 1998
***************
*** 1,9 ****
<appendix id="phpdevel">
<title>PHP development</title>
<sect1 id="phpdevel-addfunc">
<title>Adding functions to PHP3</title>
! <simpara></simpara>
<sect1 id="calling-user-functions">
<title>Calling User Functions</title>
--- 1,662 ----
<appendix id="phpdevel">
<title>PHP development</title>
+ <simpara></simpara>
+
<sect1 id="phpdevel-addfunc">
<title>Adding functions to PHP3</title>
! <sect2 id="phpdevel-addfunc-prototype">
! <title>Function Prototype</title>
! <para>
! All functions look like this:
! <programlisting>
! void php3_foo(INTERNAL_FUNCTION_PARAMETERS) {
!
! }
! </programlisting>
! Even if your function doesn't take any arguments, this is how it is
! called.
!
! <sect2 id="phpdevel-addfunc-args">
! <title>Function Arguments</title>
! <para>
! 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:
!
! <para>
! <example>
! <title>Fetching function arguments</title>
! <programlisting>
! pval *arg1, *arg2;
! if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&arg1,&arg2)==FAILURE) {
! WRONG_PARAM_COUNT;
! }
! </programlisting>
! </example>
!
! NOTE: Arguments can be passed either by value or by reference. In
! both cases you will need to pass &(pval *) to getParameters. If
! you want to check if the n'th parameter was sent to you by
! reference or not, you can use the function,
! ParameterPassedByReference(ht,n). It will return either 1 or 0.
!
! <simpara>
! 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 yystype_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.
!
! <simpara>
! 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
! yystype_destructor on it first.
!
! <sect2 id="phpdevel-addfunc-varargs">
! <title>Variable Function Arguments</title>
! <para>
! A function can take a variable number of arguments. If your function can
! take either 2 or 3 arguments, use the following:
!
! <para>
! <example>
! <title>Variable function arguments</title>
! <programlisting>
! pval *arg1, *arg2, *arg3;
! int arg_count = ARG_COUNT(ht);
!
! if (arg_count < 2 || arg_count > 3 ||
! getParameters(ht,arg_count,&arg1,&arg2,&arg3)==FAILURE) {
! WRONG_PARAM_COUNT;
! }
! </programlisting>
! </example>
!
! <sect2 id="phpdevel-addfunc-using-args">
! <title>Using the Function Arguments</title>
! <para>
! The type of each argument is stored in the pval type field. This
! type can be any of the following:
!
! <table>
! <title>PHP Internal Types</title>
! <tgroup cols="2">
! <tbody>
! <row>
! <entry>IS_STRING</entry>
! <entry>String</entry>
! </row>
! <row>
! <entry>IS_DOUBLE</entry>
! <entry>Double-precision floating point</entry>
! </row>
! <row>
! <entry>IS_LONG</entry>
! <entry>Long integer</entry>
! </row>
! <row>
! <entry>IS_ARRAY</entry>
! <entry>Array</entry>
! </row>
! <row>
! <entry>IS_EMPTY</entry>
! <entry>None</entry>
! </row>
! <row>
! <entry>IS_USER_FUNCTION</entry>
! <entry>??</entry>
! </row>
! <row>
! <entry>IS_INTERNAL_FUNCTION</entry>
! <entry>?? (if some of these cannot be passed to a function - delete)</entry>
! </row>
! <row>
! <entry>IS_CLASS</entry>
! <entry>??</entry>
! </row>
! <row>
! <entry>IS_OBJECT</entry>
! <entry>??</entry>
! </row>
! </tbody>
! </tgroup>
! </table>
!
! <para>
! 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:
!
! <programlisting>
! 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
*/
! </programlisting>
!
! <simpara>
! These function all do in-place conversion. They do not return anything.
!
! <para>
! The actual argument is stored in a union; the members are:
! <itemizedlist>
! <listitem><simpara>IS_STRING: arg1->value.str.val
! <listitem><simpara>IS_LONG: arg1->value.lval
! <listitem><simpara>IS_DOUBLE: arg1->value.dval
! </itemizedlist>
!
! <sect2 id="phpdevel-addfunc-memmgmt">
! <title>Memory Management in Functions</title>
! <simpara>
! 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().
!
! <simpara>
! 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).
!
! <simpara>
! 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.
!
! <simpara>
! If you compile with "-DDEBUG", PHP3 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.
!
! <sect2 id="phpdevel-addfunc-symtab">
! <title>Setting Variables in the Symbol Table</title>
! <para>
! A number of macros are available which make it easier to set a
! variable in the symbol table:
!
! <itemizedlist>
! <listitem><simpara>SET_VAR_STRING(name,value) <footnoteref
linkend="symtab-1">
! <listitem><simpara>SET_VAR_DOUBLE(name,value)
! <listitem><simpara>SET_VAR_LONG(name,value)
! </itemizedlist>
!
! <para>
! <footnote id="symtab-1">
! <simpara>
! Be careful here. The value part must be malloc'ed manually because
! the memory management code will try to free this pointer later. Do
! not pass statically allocated memory into a SET_VAR_STRING.
! </footnote>
!
! <simpara>
! Symbol tables in PHP 3.0 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).
!
! <para>
! 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.
!
! <para>
! <example>
! <title>Checking whether $foo exists in a symbol table</title>
! <programlisting>
! if (hash_exists(active_symbol_table,"foo",sizeof("foo"))) { exists... }
! else { doesn't exist }
! </programlisting>
! </example>
!
! <example>
! <title>Finding a variable's size in a symbol table</title>
! <programlisting>
! hash_find(active_symbol_table,"foo",sizeof("foo"),&yystype);
! check(yystype.type);
! </programlisting>
! </example>
!
! Arrays in PHP 3.0 are implemented using the same hashtables as
! symbol tables. This means the two above functions can also be
! used to check variables inside arrays.
!
! <simpara>
! If you want to define a new array in a symbol table, you should do
! the following.
!
! <simpara>
! First, you may want to check whether it exists and abort
! appropiately, using hash_exists() or hash_find().
!
! <simpara>
! Next, initialize the array:
!
! <para>
! <example>
! <title>Initializing a new array</title>
! <programlisting>
! pval arr;
!
! if (array_init(&arr) == FAILURE) { failed... };
!
hash_update(active_symbol_table,"foo",sizeof("foo"),&arr,sizeof(pval),NULL);
! </programlisting>
! </example>
!
! This code declares a new array, named $foo, in the active symbol
! table. This array is empty.
!
! <simpara>
! Here's how to add new entries to it:
!
! <para>
! <example>
! <title>Adding entries to a new array</title>
! <programlisting>
! pval entry;
!
! entry.type = IS_LONG;
! entry.value.lval = 5;
!
! /* defines $foo["bar"] = 5 */
!
hash_update(arr.value.ht,"bar",sizeof("bar"),&entry,sizeof(pval),NULL);
!
! /* defines $foo[7] = 5 */
! hash_index_update(arr.value.ht,7,&entry,sizeof(pval),NULL);
!
! /* defines the next free place in $foo[],
! * $foo[8], to be 5 (works like php2)
! */
! hash_next_index_insert(arr.value.ht,&entry,sizeof(pval),NULL);
! </programlisting>
! </example>
!
! If you'd like to modify a value that you inserted to a hash, you
! must first retrieve it from the hash. To prevent that overhead,
! you can supply a pval ** to the hash add function, and it'll be
! updated with the pval * address of the inserted element inside the
! hash. If that value is NULL (like in all of the above examples) -
! that parameter is ignored.
!
! <simpara>
! hash_next_index_insert() uses more or less the same logic as
! "$foo[] = bar;" in PHP 2.0.
!
! <simpara>
! If you are building an array to return from a function, you can
! initialize the array just like above by doing:
!
! <programlisting>
! if (array_init(return_value) == FAILURE) { failed...; }
! </programlisting>
!
! <simpara>
! ...and then adding values with the helper functions:
!
! <programlisting>
! 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));
! </programlisting>
!
! <para>
! Of course, if the adding isn't done right after the array
! initialization, you'd probably have to look for the array first:
!
! <programlisting>
! pval *arr;
!
! if (hash_find(active_symbol_table,"foo",sizeof("foo"),(void
**)&arr)==FAILURE) { can't find... }
! else { use arr->value.ht... }
! </programlisting>
!
! <simpara>
! Note that hash_find receives a pointer to a pval pointer, and not
! a pval pointer.
!
! <simpara>
! Just about any hash function returns SUCCESS or FAILURE (except
! for hash_exists(), which returns a boolean truth value).
!
! <sect2 id="phpdevel-addfunc-retsimple">
! <title>Returning simple values</title>
! <simpara>
! A number of macros are available to make returning values from a
! function easier.
!
! <para>
! The RETURN_* macros all set the return value and return from the
! function:
! <itemizedlist>
! <listitem><simpara>RETURN
! <listitem><simpara>RETURN_FALSE
! <listitem><simpara>RETURN_TRUE
! <listitem><simpara>RETURN_LONG(l)
! <listitem><simpara>RETURN_STRING(s,dup) If dup is true, duplicates the string
! <listitem><simpara>RETURN_STRINGL(s,l,dup) Return string (s) specifying length
(l).
! <listitem><simpara>RETURN_DOUBLE(d)
! </itemizedlist>
!
! <para>
! The RETVAL_* macros set the return value, but do not return.
! <itemizedlist>
! <listitem><simpara>RETVAL_FALSE
! <listitem><simpara>RETVAL_TRUE
! <listitem><simpara>RETVAL_LONG(l)
! <listitem><simpara>RETVAL_STRING(s,dup) If dup is true, duplicates the string
! <listitem><simpara>RETVAL_STRINGL(s,l,dup) Return string (s) specifying length
(l).
! <listitem><simpara>RETVAL_DOUBLE(d)
! </itemizedlist>
!
! <simpara>
! 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.
!
! <simpara>
! If your function returns boolean success/error responses, always
! use RETURN_TRUE and RETURN_FALSE respectively.
!
! <sect2 id="phpdevel-addfunc-retcomplex">
! <title>Returning complex values</title>
! <simpara>
! Your function can also return a complex data type such as an
! object or an array.
!
! <para>
! Returning an object:
!
! <orderedlist numeration="arabic">
! <listitem><simpara>Call object_init(return_value).
! <listitem><para>Fill it up with values. The functions available
! for this purpose are listed below.
! <listitem><para> 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:
! <programlisting>
! add_method( return_value, function_name, function_ptr );
! </programlisting>
! </orderedlist>
!
! <para>
! The functions used to populate an object are:
! <itemizedlist>
! <listitem><simpara>add_property_long( return_value,
! property_name, l ) - Add a property named 'property_name', of
! type long, equal to 'l'
! <listitem><simpara>add_property_double( return_value,
! property_name, d ) - Same, only adds a double
! <listitem><simpara>add_property_string( return_value,
! property_name, str ) - Same, only adds a string
! <listitem><simpara>add_property_stringl( return_value,
! property_name, str, l ) - Same, only adds a string of length 'l'
! </itemizedlist>
!
! <para>
! Returning an array:
!
! <orderedlist numeration="arabic">
! <listitem><simpara>Call array_init(return_value).
! <listitem><simpara>Fill it up with values. The functions available
! for this purpose are listed below.
! </orderedlist>
!
! <para>
! The functions used to populate an array are:
! <itemizedlist>
! <listitem><simpara>add_assoc_long(return_value,key,l) - add
! associative entry with key 'key' and long value 'l'
! <listitem><simpara>add_assoc_double(return_value,key,d)
! <listitem><simpara>add_assoc_string(return_value,key,str)
! <listitem><simpara>add_assoc_stringl(return_value,key,str,length)
! specify the string length
! <listitem><simpara>add_index_long(return_value,index,l) - add
! entry in index 'index' with long value 'l'
! <listitem><simpara>add_index_double(return_value,index,d)
! <listitem><simpara>add_index_string(return_value,index,str)
! <listitem><simpara>add_index_stringl(return_value,index,str,length)
! - specify the string length
! <listitem><simpara>add_next_index_long(return_value,l) - add an
! array entry in the next free offset with long value 'l'
! <listitem><simpara>add_next_index_double(return_value,d)
! <listitem><simpara>add_next_index_string(return_value,str)
! <listitem><simpara>add_next_index_stringl(return_value,str,length)
! - specify the string length
! </itemizedlist>
!
! <sect2 id="phpdevel-addfunc-reslist">
! <title>Using the resource list</title>
! <simpara>
! PHP 3.0 has a standard way of dealing with various types of
! resources. This replaces all of the local linked lists in PHP 2.0.
!
! <para>
! Available functions:
!
! <itemizedlist>
! <listitem><simpara>php3_list_insert(ptr, type) - returns the 'id'
! of the newly inserted resource
! <listitem><simpara>php3_list_delete(id) - delete the resource
! with the specified id
! <listitem><simpara>php3_list_find(id,*type)
! - returns the pointer of the resource with the specified id,
! updates 'type' to the resource's type
! </itemizedlist>
!
! Typically, these functions are used for SQL drivers but they can
! be used for anything else; for instance, maintaining file
! descriptors.
!
! <simpara>
! Typical list code would look like this:
!
! <para>
! <example>
! <title>Adding a new resource</title>
! <programlisting>
! RESOURCE *resource;
!
! /* ...allocate memory for resource and acquire resource... */
! /* add a new resource to the list */
! return_value->value.lval = php3_list_insert((void *) resource, LE_RESOURCE_TYPE);
! return_value->type = IS_LONG;
! </programlisting>
! </example>
!
! <example>
! <title>Using an existing resource</title>
! <programlisting>
! pval *resource_id;
! RESOURCE *resource;
! int type;
!
! convert_to_long(resource_id);
! resource = php3_list_find(resource_id->value.lval, &type);
! if (type != LE_RESOURCE_TYPE) {
! php3_error(E_WARNING,"resource index %d has the wrong
type",resource_id->value.lval);
! RETURN_FALSE;
! }
! /* ...use resource... */
! </programlisting>
! </example>
!
! <example>
! <title>Deleting an existing resource</title>
! <programlisting>
! pval *resource_id;
! RESOURCE *resource;
! int type;
!
! convert_to_long(resource_id);
! php3_list_delete(resource_id->value.lval);
! </programlisting>
! </example>
!
! The resource types should be registered in php3_list.h, in enum
! list_entry_type. In addition, one should add shutdown code for
! any new resource type defined, in list.c's list_entry_destructor()
! (even if you don't have anything to do on shutdown, you must add
! an empty case).
!
! <sect2 id="phpdevel-addfunc-prestable">
! <title>Using the persistent resource table</title>
! <para>
! PHP 3.0 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:
!
! <simplelist>
! <member>php3_mysql_do_connect</member>
! <member>php3_mysql_connect()</member>
! <member>php3_mysql_pconnect()</member>
! </simplelist>
!
! <para>
! The general idea of persistence modules is this:
! <orderedlist numeration="arabic">
! <listitem><simpara>Code all of your module to work with the
! regular resource list mentioned in section (9).
! <listitem><simpara>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).
! </orderedlist>
!
! <simpara>
! 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.
!
! <simpara>
! The very same interface exists for the regular resource list and
! the persistent resource list, only 'list' is replaced with
! 'plist':
!
! <itemizedlist>
! <listitem><simpara>php3_plist_insert(ptr, type) - returns the 'id'
! of the newly inserted resource
! <listitem><simpara>php3_plist_delete(id) - delete the resource
! with the specified id
! <listitem><simpara>php3_plist_find(id,*type)
! - returns the pointer of the resource with the specified id,
! updates 'type' to the resource's type
! </itemizedlist>
!
! <simpara>
! 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.
!
! <simpara>
! Until further documented, you should look at mysql.c or msql.c to
! see how one should use the plist's hash table abilities.
!
! <simpara>
! 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.
!
! <simpara>
! 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 destructotion 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.
!
!
! <sect2 id="phpdevel-addfunc-addcfg">
! <title>Adding runtime configuration directives</title>
! <para>
! Many of the features of PHP3 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.
!
! <para>
! The steps required to add a new directive:
!
! <orderedlist>
! <listitem><simpara>Add directive to php3_ini_structure struct in mod_php3.h.
!
! <listitem><simpara>In main.c, edit the php3_module_startup
! function and add the appropriate cfg_get_string() or
! cfg_get_long() call.
!
! <listitem><simpara>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.
!
! <listitem><simpara>In either php3take1handler() or
! php3flaghandler() add the appropriate entry for your directive.
!
! <listitem><simpara>In the configuration section of the
! _php3_info() function in functions/info.c you need to add your
! new directive.
!
! <listitem><simpara>And last, you of course have to use your new
! directive somewhere. It will be addressable as
! php3_ini.directive.
! </orderedlist>
!
<sect1 id="calling-user-functions">
<title>Calling User Functions</title>
--
PHP Development Mailing List http://www.php.net/
To unsubscribe send an empty message to php-dev-unsubscribe@lists.php.net
For help: php-dev-help@lists.php.net