Implementation method of calling C code in php_PHP tutorial

WBOY
Release: 2016-07-13 10:36:13
Original
792 people have browsed it

C code needs to be used in the php program, which should be the following two situations:

1 I already have C code and want to use it directly in the PHP program
2 Due to performance issues with PHP, I need to use C to implement some functions

For the first situation, the most appropriate method is to use system calls to write the existing C code into an independent program. Parameters are passed in through the command line or standard input, and the results are read from standard output. Secondly, the slightly more troublesome method is to write C code as a daemon, and the PHP program uses socket to communicate with it.

Focus on the second case. Although it is also possible to use the system call method, consider that your purpose is to optimize performance. Starting so many processes so frequently will of course degrade performance. The method of writing a daemon is certainly feasible, but it is much more complicated.

My simple test shows that the same algorithm is 500 times more efficient when written in C than in PHP. And using PHP extension can also improve it by more than 90 times (the performance loss is in parameter passing, I guess).

So sometimes php extension is our best choice.

Here I will focus on how to write PHP extensions in C without recompiling PHP.

First of all, find a php source code. It can be php4 or php5 version. It has nothing to do with the php version of your target platform.

You can find a script named ext_skel in the ext directory of the source code (windows platform uses ext_skel_win32.php)
Execute ./ext_skel --extname=hello in this directory (I use hello as an example)
At this time, a directory hello is generated. There are several files in the directory. You only need to care about these three: config.m4 hello.c php_hello.h

Copy this directory to wherever you want, cd into it, and execute
phpize
/configure
make
in sequence. Nothing happens, right?
This is because you missed a step. Open config.m4 and find the following
dnl If your extension references something external, use with:
..
dnl Otherwise use enable:
..
This allows you to choose whether your extension uses with or enable. Let’s use with. Uncomment the with part.
If you use the vim editor like me, you will easily find that the three letters dnl originally represent comments (this is because vim comes with syntax coloring packages for various file formats by default)

After we modify config.m4, continue
phpize
/configure
make
At this time, hello.so and hello.la files will be generated under modules. One is a dynamic library and the other is a static library.

Your php extension is ready, although it has not yet achieved the function you want. Let me first talk about how to use this extension! ext_skel generated a hello.php for you with a calling example, but that example requires you to copy hello.so to the extension directory of PHP. We just want to implement our own functions and don't want to create a copycat version of PHP. Instead, use the following To load it:

Copy the code The code is as follows:

if(!extension_loaded("hello")) {
        dl_local("hello.so");
}
function dl_local( $extensionFile ) {
        //make sure that we are ABLE to load libraries06.        if( !(bool)ini_get( "enable_dl" ) || (bool)ini_get( "safe_mode" ) ) {
                die( "dh_local(): Loading extensions is not permitted./n" );
        }
        //check to make sure the file exists11.        if( !file_exists(dirname(__FILE__) . "/". $extensionFile ) ) {
                die( "dl_local(): File '$extensionFile' does not exist./n" );
        }
        //check the file permissions16.        if( !is_executable(dirname(__FILE__) . "/". $extensionFile ) ) {
                die( "dl_local(): File '$extensionFile' is not executable./n" );
        }
        //we figure out the path21.        $currentDir = dirname(__FILE__) . "/";
        $currentExtPath = ini_get( "extension_dir" );
        $subDirs = preg_match_all( "////" , $currentExtPath , $matches );
        unset( $matches );
        //lets make sure we extracted a valid extension path27.        if( !(bool)$subDirs ) {
                die( "dl_local(): Could not determine a valid extension path [extension_dir]./n" );
        }
        $extPathLastChar = strlen( $currentExtPath ) - 1;
        if( $extPathLastChar == strrpos( $currentExtPath , "/" ) ) {
                $subDirs--;
        }
        $backDirStr = "";
        for( $i = 1; $i <= $subDirs; $i++ ) {
                $backDirStr .= "..";
                if( $i != $subDirs ) {
                  $backDirStr .= "/";
                }
        }
        //construct the final path to load46.        $finalExtPath = $backDirStr . $currentDir . $extensionFile;
        //now we execute dl() to actually load the module49.        if( !dl( $finalExtPath ) ) {
                die();
        }
        //if the module was loaded correctly, we must bow grab the module name54.        $loadedExtensions = get_loaded_extensions();
        $thisExtName = $loadedExtensions[ sizeof( $loadedExtensions ) - 1 ];
        //lastly, we return the extension name58.        return $thisExtName;
}//end dl_local()

The advantage of this is that your php extension can follow your php code, which is a green extension.

The next question that people are concerned about is how to add functions, implement parameter transfer and return values

The steps to add a function are as follows:
php_hello.h:
PHP_FUNCTION(confirm_hello_compiled);// Fill in the function name in the brackets

hello.c
zend_function_entry hello_functions[] = {
PHP_FE(confirm_hello_compiled, NULL) /* Add a line here*/
{NULL, NULL, NULL} /* Must be the last line in hello_functions [] */
};
PHP_FUNCTION(confirm_hello_compiled)
{// Write the function body here
}
The function prototypes to be implemented are actually the same, and they are packaged with the macro PHP_FUNCTION , In addition, a line of information is added to hello_functions, indicating that you have this function in this module.

So they all have the same function prototype, how to distinguish the return value and parameters?
I will give you an example:

Copy code The code is as follows:

PHP_FUNCTION(hello_strdiff)
{
char *r1 = NULL, *r2 = NULL;
int n = 0, m = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &r1, &n, &r2, &m) == Failure) {
Return;
}
While (n && m && *r1 == *r2) {
r1 ++;
r2 ++;
n-; --;
}
if(n == 0) RETURN_LONG(m);
if(m == 0) RETURN_LONG(n);
int d[n+1][m+ 1];
int cost;
int i,j;
for(i = 0; i <= n; i++) d[i][0] = i;
for(j = 0; j <= m; j++) d[0][j] = j;
for(i = 1; i <= n; i++) {
for(j = 1; j < ;= m; j++) {
                                                                                                                                                                                 -1][j]+1,d[i][j-1]+1);
         a = MIN(a, d[i-1][j-1]+cost);
            d [i][j] = a;
}
}
RETURN_LONG(d[n][m]);
}


这是一个求两个字符串差异度的算法,输入参数两个字符串,返回整型。
参数的传递看这里
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &r1, &n, &r2, &m)

把这个当成是scanf来理解好了。
类型说明见下表:

Boolean b zend_bool
Long l long
Double d double
String s char*, int
Resource r zval*
Array a zval*
Object o zval*
zval z zval*

如果想实现可选参数的话,例如一个字符串,一个浮点,再加一个可选的bool型,可以用"sd|b"来表示。
和scanf有一点不同的是,对于字符串,你要提供两个变量来存储,一个是char *,存字符串的地址,一个int,来存字符串的长度。这样有必要的时候,你可以安全的处理二进制数据。

那么返回值怎么办呢?
使用下面一组宏来表示:

RETURN_STRING
RETURN_LONG
RETURN_DOUBLE
RETURN_BOOL
RETURN_NULL

注意RETURN_STRING有两个参数
当你需要复制一份字符串时使用
RETURN_STRING("Hello World", 1);

否则使用
RETURN_STRING(str, 0);

这里涉及到了模块中内存的分配,当你申请的内存需要php程序中去释放的话,请参照如下表

Traditional Non-Persistent Persistent
malloc(count)
calloc(count, num)
emalloc(count)
ecalloc(count, num)
pemalloc(count, 1)*
pecalloc(count, num, 1)
strdup(str)
strndup(str, len)
estrdup(str)
estrndup(str, len)
pestrdup(str, 1)
pemalloc() & memcpy()
free(ptr) efree(ptr) pefree(ptr, 1)
realloc(ptr, newsize) erealloc(ptr, newsize) perealloc(ptr, newsize, 1)
malloc(count * num + extr)** safe_emalloc(count, num, extr) safe_pemalloc(count, num, extr)

Generally we use the ones listed in Non-Persistent.

That’s basically it, you can start writing a php extension.
From my current application point of view, being able to manipulate strings is enough, so I can only introduce so much.

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/740214.htmlTechArticleWhen you need to use C code in a php program, there should be the following two situations: 1. There is already C code. I want to use 2 directly in the php program. Due to the performance issues of php, I need to use C to implement some functions. For the first...
Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template