Programming PHPProgramming PHPSearch this book

14.8. Returning Values

Knowing how to get data into a function is only one side of the problem—how do you get it out? This section shows you how to return values from an extension function, from simple strings or numbers all the way up to arrays and objects.

14.8.1. Simple Types

Returning a value from a function back to the script involves populating the special, preallocated return_value container. For example, this returns an integer:

PHP_FUNCTION(foo) {
    Z_LVAL_P(return_value) = 99;
    Z_TYPE_P(return_value) = IS_LONG;
}

Since returning a single value is such a common task, there are a number of convenience macros to make it easier. The following code uses a convenience macro to return an integer:

PHP_FUNCTION(foo) {
    RETURN_LONG(99);
}

The RETURN_LONG( ) macro fills in the container and immediately returns. If for some reason we wanted to populate the return_value container and not return right away, we could use the RETVAL_LONG( ) macro instead.

Returning a string is almost as simple with the convenience macros:

PHP_FUNCTION(rt13) {
    RETURN_STRING("banana", 1);
}   

The last argument specifies whether or not the string needs to be duplicated. In that example it obviously does, but if we had allocated the memory for the string using an emalloc( ) or estrdup( ) call, we wouldn't need to make a copy:

PHP_FUNCTION(rt13) {
    char *str = emalloc(7);
    strcpy(str, "banana");
    RETURN_STRINGL(str, 6, 0);
}

Here we see an example of doing our own memory allocation and also using a version of the RETURN macro that takes a string length. Note that we do not include the terminating NULL in the length of our string.

The available RETURN-related convenience macros are listed in Table 14-4.

Table 14-4. RETURN-related convenience macros

RETURN_RESOURCE(int r)
RETVAL_RESOURCE(int r)
RETURN_BOOL(int b) 
RETVAL_BOOL(int b)
RETURN_NULL( ) 
RETVAL_NULL( )
RETURN_LONG(int l) 
RETVAL_LONG(int l)
RETURN_DOUBLE(double d) 
RETVAL_DOUBLE(double d)
RETURN_STRING(char *s, int dup) 
RETVAL_STRING(char *s, int dup)
RETURN_STRINGL(char *s, int l, int dup) 
RETVAL_STRINGL(char *s, int l, int dup)
RETURN_EMPTY_STRING( ) 
RETVAL_EMPTY_STRING( )
RETURN_FALSE 
RETVAL_FALSE
RETURN_TRUE 
RETVAL_TRUE

14.8.2. Arrays

To return an array from a function in your extension, initialize return_value to be an array and then fill it with elements. For example, this returns an array with "123" in position 0:

PHP_FUNCTION(my_func) {
  array_init(return_value);
  add_index_long(return_value, 0, 123);
}

Call your function from a PHP script like this:

$arr = my_func( );  // $arr[0] holds 123

To add a string element to the array:

add_index_string(return_value, 1, "thestring", 1);

This would result in:

$arr[1] = "thestring"

If you have a static string whose length you know already, use the add_index_stringl( ) function:

add_index_stringl(return_value, 1, "abc", 3, 1);

The final argument specifies whether or not the string you provide should be copied. Normally, you would set this to 1. The only time you wouldn't is when you have allocated the memory for the string yourself, using one of PHP's emalloc( )-like functions. For example:

char *str;
str = estrdup("abc");
add_index_stringl(return_value, 1, str, 3, 0);

There are three basic flavors of array-insertion functions: inserting at a specific numeric index, inserting at the next numeric index, and inserting at a specific string index. These flavors exist for all data types.

Inserting at a specific numeric index ($arg[$idx] = $value) looks like this:

add_index_long(zval *arg, uint idx, long n)
add_index_null(zval *arg, uint idx)
add_index_bool(zval *arg, uint idx, int b)
add_index_resource(zval *arg, uint idx, int r)
add_index_double(zval *arg, uint idx, double d)
add_index_string(zval *arg, uint idx, char *str, int duplicate)
add_index_stringl(zval *arg, uint idx, char *str, uint length, int duplicate)
add_index_zval(zval *arg, uint index, zval *value)

Inserting at the next numeric index ($arg[] = $value) looks like this:

add_next_index_long(zval *arg, long n)
add_next_index_null(zval *arg)
add_next_index_bool(zval *, int b)
add_next_index_resource(zval *arg, int r)
add_next_index_double(zval *arg, double d)
add_next_index_string(zval *arg, char *str, int duplicate)
add_next_index_stringl(zval *arg, char *str, uint length, int duplicate)
add_next_index_zval(zval *arg, zval *value)

And inserting at a specific string index ($arg[$key] = $value) looks like this:

add_assoc_long(zval *arg, char *key, long n)
add_assoc_null(zval *arg, char *key)
add_assoc_bool(zval *arg, char *key, int b)
add_assoc_resource(zval *arg, char *key, int r)
add_assoc_double(zval *arg, char *key, double d)
add_assoc_string(zval *arg, char *key, char *str, int duplicate)
add_assoc_stringl(zval *arg, char *key, char *str, uint length, int duplicate)
add_assoc_zval(zval *arg, char *key, zval *value)

14.8.3. Objects

Returning an object requires you to define the object first. Defining an object from C involves creating a variable corresponding to that class and building an array of functions for each of the methods. The MINIT( ) function for your extension should register the class.

The following code defines a class and returns an object:

static zend_class_entry *my_class_entry_ptr;
  
static zend_function_entry php_my_class_functions[] = {
    PHP_FE(add, NULL)
    PHP_FALIAS(del, my_del, NULL)
    PHP_FALIAS(list, my_list, NULL)
/* ... */
};
  
PHP_MINIT_FUNCTION(foo)
{
    zend_class_entry foo_class_entry;
  
    INIT_CLASS_ENTRY(foo_class_entry, "my_class", php_foo_class_functions);
    foo_class_entry_ptr =
      zend_register_internal_class(&foo_class_entry TSRMLS_CC);
    /* ... */
  
PHP_FUNCTION(my_object) {
    object_init_ex(return_value, foo_class_entry_ptr);
    add_property_long(return_value,"version",
                      foo_remote_get_version(XG(session)));
    add_property_bool(...)
    add_property_string(...)
    add_property_stringl(...)
    ...

From the user space, you would then have:

$obj = my_object( );
$obj->add( );

If instead you want traditional instantiation, like this:

$obj = new my_class( );

use the automatically initialized this_ptr instead of return_value:

PHP_FUNCTION(my_class) {
    add_property_long(this_ptr, "version",
                      foo_remote_get_version(XG(session)));
    add_property_bool(...)
    add_property_string(...)
    add_property_stringl(...)
    ...

You can access class properties from the various functions and methods like this:

zval **tmp;
if(zend_hash_find(HASH_OF(this_ptr), "my_property", 12, 
    (void **)&tmp) == SUCCESS) {
        convert_to_string_ex(tmp);
        printf("my_property is set to %s\n", Z_STRVAL_PP(status));
}

You can set/update a class property as follows:

add_property_string(this_ptr, "filename", fn, 1);
add_property_stringl(this_ptr, "key", "value", 5, 1);
add_property_bool(this_ptr, "toggle", setting?0:1); 
add_property_long(this_ptr, "length", 12345);
add_property_double(this_ptr, "price", 19.95);




Library Navigation Links

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