Search code examples
phpcphp-extension

PHP. Extension. Call existing PHP function


So I decided to write an extension for php. Everything seems to be fine except I'm stuck on a tiny problem.

I have php-5.4.9 source codes. There is file ext/standard/mail.c with awesome function

PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd TSRMLS_DC)

In my extension, in acme.c I have includes

...
#include "php.h"
#include "ext/standard/php_mail.h"
#include "php_ini.h"
...

So php_mail feels good and works fine. But, obviously, I want to use the code from mail.c starting on line 101 and ending on 189 (http://pastie.org/5444192 5-93 corresponding lines in the paste). So I caught myself on idea (it is awkward in some point though) why not to call PHP_FUNCTION(mail)? By the moment I could not locate that macros, and actually I'd like to know the best way to implement the idea.

My inner zend engineer (which is newbie) recommends me to use call_user_function

ZEND_API int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC);

But I can not figure it out how to call it.

The question! How (an example with mail function is very welcomed) to call functions defined by PHP_FUNCTION?


Solution

  • The easiest way to figure out how a function works is to search for it on lxr.php.net. The first example that turns up is in readline: http://lxr.php.net/xref/PHP_TRUNK/ext/readline/readline.c#474

    The use for mail is analogous. Given the arguments as zvals (to_zval, from_zval, msg_zval) the call is very simple:

    zval *params = { to_zval, from_zval, msg_zval };
    zend_uint param_count = 3;
    zval *retval_ptr;
    
    zval function_name;
    INIT_ZVAL(function_name);
    ZVAL_STRING(&function_name, "mail", 1);
    
    if (call_user_function(
            CG(function_table), NULL /* no object */, &function_name,
            retval_ptr, param_count, params TSRMLS_CC
        ) == SUCCESS
    ) {
        /* do something with retval_ptr here if you like */
    }
    
    /* don't forget to free the zvals */
    zval_ptr_dtor(&retval_ptr);
    zval_dtor(&function_name);
    

    If you don't have the parameters as zvals already, then you can create them using MAKE_STD_ZVAL and ZVAL_STRING.