PHP. Extension. Call existing PHP function
Asked Answered
N

1

19

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?

Niddering answered 27/11, 2012 at 19:58 Comment(1)
Can you explain elaborate on the use case for calling php_mail() from your extension? It sounds like your extension is trying to do too much, and that either more of it should be written in PHP or you should be compiling this to a standalone binary. Remember, PHP extensions should be generic and re-usable, not tied to a specific application. Can you explain a little more about what this extension does?Photochemistry
M
20

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.

Malevolent answered 27/11, 2012 at 21:28 Comment(3)
Hmm, handy, I'd not seen lxr.php.net. It's sad that this is the easiest approach to finding your way around the api though!Susian
Could I call functions like this, PHPAPI or PHP_FUNCTION, from a stand-alone binary? Or must they be in a PHP extension?Escobedo
@Malevolent is this answer still correct for PHP 7+?Kersey

© 2022 - 2024 — McMap. All rights reserved.