Appel des fonctions utilisateurs

Vous pouvez appeler des fonctions utilisateurs depuis vos propres modules, ce qui est très maniable lors de l'implémentation de callbacks ; par exemple, pour parcourir ou rechercher dans un tableau, ou simplement pour les évènements de vos programmes.

Les fonctions utilisateurs peuvent être appelées avec la fonction call_user_function_ex(). Elle requiet une valeur de hashage pour la table de fonction dont vous voulez accéder, un pointeur vers un objet (si vous voulez appeler une méthode), le nom de la fonction, la valeur retournée, le nombre d'arguments, un tableau d'arguments, et un flag indiquant si oui ou non vous voulez effectuer une séparation zval.

ZEND_API int call_user_function_ex(HashTable *function_table, zval *object,
zval *function_name, zval **retval_ptr_ptr,
int param_count, zval **params[],
int no_separation);

Notez que vous n'avez pas besoin de spécifier à la fois function_table et object ; l'un ou l'autre suffit. Si vous voulez appeler une méthode, vous devez fournir l'objet qui contient cette méthode, et dans ce cas, call_user_function() définit automatiquement la table de fonction à cette objet. Sinon, vous ne devez spécifier que function_table et vous pouvez définir object à NULL.

Habituellement, la table de fonction par défaut est la table de fonction "root" contenant toutes les entrées de fonction. Cette table de fonction est une partie du compilateur global et peut être accéder en utilisant la macro CG. Pour introduite le compilateur globale à votre fonction, appeler d'abord la macro TSRMLS_FETCH.

Le nom de la fonction est spécifié dans un conteneur zval. Ceci peut paraître surprenant dans un premier temps, mais c'est une étape logique, car la plupart des fois, vous accepterez des noms de fonctions en tant queparamètres pour l'appel des fonctions dans votre script, qui seront eux-même dans un conteneur zval. Vous n'avez qu'à passer vos arguments via cette fonction. Ce conteneur zval doit être du type IS_STRING.

Le prochain argument consiste en un pointeur de la valeur retournée. Vous n'avez pas à allouer de mémoire pour ce conteneur ; la fonction le fera elle-même. Cependant, vous devez ensuite détruire ce conteneur (en utilisant la fonction zval_dtor()) !

Le prochain est le paramètre de compteur (un entier) et un tableau contenant tous les paramètres nécessaires. Le dernier argument indique si la fonction doit effectuer une séparation zval - il doit toujours être défini à 0. Si défini à 1, la fonction consomme moins de mémoire mais échoue si un des paramètres doit être séparer.

Exemple 46-15 montre une petite démonstration de l'appel d'une fonction utilisateur. Le code appelle une fonction qui lui est fournie en tant qu'argument et passe directement la valeur retournée par cette fonction via sa propre valeur retournée. Notez l'utilisation du constructeur et du destructeur à la fin - cela peut ne pas être nécessaire ici (car les valeurs doivent être séparées, l'assignement est sécurisé), mais c'est plus prudent.

Exemple 46-15. Appeler des fonctions utilisateurs

zval **function_name;
zval *retval;

if((ZEND_NUM_ARGS() != 1) || (zend_get_parameters_ex(1, &function_name) != SUCCESS))
{
    WRONG_PARAM_COUNT;
}

if((*function_name)->type != IS_STRING)
{
    zend_error(E_ERROR, "La fonction requiet une chaîne de caractères en tant qu'argument.");
}

TSRMSLS_FETCH();

if(call_user_function_ex(CG(function_table), NULL, *function_name, &retval, 0, NULL, 0) != SUCCESS)
{
    zend_error(E_ERROR, "L'appel à la fonction a échoué");
}

zend_printf("We have %i as type<br />", retval->type);

*return_value = *retval;
zval_copy_ctor(return_value);
zval_ptr_dtor(&retval);

<?php

dl("call_userland.so");

function test_function()
{

    print("Nous sommes dans une fonction de test !<br />");

    return("hello");

}

$return_value = call_userland("test_function");

print("Valeur retournée : \"$return_value\"<br />");
?>