Programming PHPProgramming PHPSearch this book

14.7. Parameter Handling

As we learned in the previous section on the pval/zval container, there are at least two ways to accept and parse arguments to PHP functions you write. We will concentrate on the higher-level zend_parse_parameters( ) function here.

There are two versions of the function, prototyped like this in C:

int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...);
int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, 
  char *type_spec, ...);

They differ only in that the ex, or expanded, version of the function contains a flags parameter. The only flag currently supported is ZEND_PARSE_PARAMS_QUIET, which inhibits warnings from supplying an incorrect number or type of arguments.

Both parameter-parsing functions return either SUCCESS or FAILURE. The functions take any number of extra arguments (pointers to variables whose values are assigned by the parsing function). On failure the return_value of the function is automatically set to FALSE, so you can simply return from your function on a failure.

The most complex part of these functions is the type_spec string you pass them. Here's the relevant part of our rot13 example:

char *arg = NULL;
int arg_len, argc = ZEND_NUM_ARGS( );
if (zend_parse_parameters(argc TSRMLS_CC, "s/", &arg, &arg_len) == FAILURE)
    return;

We first get the number of arguments passed to this function by calling the ZEND_NUM_ARGS( ) macro. We pass this number along with a type_spec string of "s/" and then the address of a char * and the address of an int. The "s" in the type_spec string indicates that we are expecting a string argument. For each string argument, the function fills in the char * and int with the contents of the string and the length of the string. The "/" character in the type_spec indicates that the string should be separated from the calling container. We did this in our rot13 example because we wanted to modify the passed string.

The other type_spec specifying characters are given in Table 14-2.

Table 14-2. Type specification characters

Character

Description

l

Long

d

Double

s

String (with possible NUL-bytes) and its length

b

Boolean, stored in zend_bool

r

Resource (stored in zval)

a

Array

o

Object (of any type)

O

Object (of specific type, specified by class entry)

z

The actual zval

The modifiers that can follow each of these are given in Table 14-3.

Table 14-3. Type specification modifiers

Modifier

Description

|

This indicates that all remaining parameters will be optional. Remember to initialize these yourself if they are not passed by the user. These functions will not put any default values in the parameters.

/

This indicates that the preceding parameter should be separated from the calling parameter, in case you wish to modify it locally in the function without modifying the original calling parameter.

!

This applies only to zval parameters (a, o, O, r, and z) and indicates that the parameter it follows can be passed a NULL. If the user does pass a NULL, the resulting container is set to NULL.

14.7.1. A Simple Example

The following code gets a long (all integers in PHP are longs), a string, and an optional double (all floating-point values in PHP are double-precision):

long l;  
char *s;
int s_len;
double d = 0.0;
if (zend_parse_parameters(ZEND_NUM_ARGS( ) TSRMLS_CC, "ls|d", &l, &s, &s_len)
    == FAILURE) return;

From a PHP script, this function might be called like this:

$num = 10; $desc = 'This is a test'; $price = 69.95;
add_item($num, $desc);          // without the optional third argument
add_item($num, $desc, $price);  // with the optional third argument

This results in long l being set to 10, char *s containing the string "This is a Test", and s_len being set to 14. For the first call, double d maintains the default 0.0 value that you set, but in the second call, where the user provides an argument, it is set to 69.95.

14.7.2. A More Complex Example

Here's an example that forces the function to fetch only the first three parameters: an array, a Boolean, and an object. We are using 'O' and also supplying an object type, which we can check in case we want to accept only a certain class of object.

zval *arr;
zend_bool b;
zval *obj;
zend_class_entry obj_ce;
if (zend_parse_parameters(3 TSRMLS_CC, "abO", &arr, &b, &obj,
                          obj_ce) == FAILURE) {
    return;
}

Forcing them to fetch only three parameters is useful for functions that can take a variable amount of parameters. You can then check the total number of arguments passed to see if there are any further arguments to process.

14.7.3. An Example with Variable Argument List

The following code illustrates how to process a variable argument list. It uses zend_parse_parameters( ) to fetch the first argument and reads further arguments into a zval *** array, then puts all the passed parameters into a PHP array and returns them:

PHP_FUNCTION(foo) {
    long arg;
    zval ***args;
    int i, argc = ZEND_NUM_ARGS( );
    
    if (zend_parse_parameters(1 TSRMLS_CC, "l", &arg) == FAILURE) return;
  
    array_init(return_value);
    add_index_long(return_value, 0, arg);
  
    if(argc>1) {
        args = (zval ***)emalloc(argc * sizeof(zval **));
        if(zend_get_parameters_array_ex(argc, args) == FAILURE) {
            efree(args);
            return;
        }
        for(i = 1; i < argc; i++) {
            zval_add_ref(args[i]);
            add_index_zval(return_value,i, *args[i]);
        }
        efree(args);
    }
}

The zval_add_ref( ) call increments the reference count of the zval container. It is explained in detail in Section 14.9 section.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.