In the PHP program needs to use the C code, should be the following two kinds of cases:
1 already have C code, in PHP program want to use directly
2 due to PHP performance problems, need to use C to achieve some of the functions
In the first case, the most appropriate approach is to use system calls to write the existing C code as a separate program. The parameters are passed through the command line or standard input, and the results are read from the standard output. Second, a little bit of trouble is the C code written in a daemon,php program with the socket to communicate with it.
Focus on the second case, although it's OK to follow the system call method, but think about your goal of optimizing performance, so many processes are so frequent that it will certainly degrade performance. and write daemon method is feasible, but cumbersome a lot.
My simple test, the same algorithm, using C to write than PHP efficiency can be improved 500 times times. And the way to expand in PHP, can also improve 90 times (which performance loss in the parameters of the pass, I guess).
So sometimes the PHP extension is our best choice.
Here I highlight the use of C to write the PHP extension method, and do not need to recompile PHP.
First of all, find a PHP source code, PHP4 or PHP5 version of all can, and your target platform of the PHP version has no relationship.
In the source of the Ext directory can find a script named Ext_skel (Windows platform using ext_skel_win32.php)
Execute in this directory./ext_skel--extname=hello (I use Hello as an example)
This generates a directory hello, there are several files under the directory, you only need to care about these three: Config.m4 hello.c php_hello.h
Copy the catalogue to any place you wish, CD in, and execute it sequentially.
Phpize
/configure
Make
Nothing happened, did it?
This is because of a missed step, open CONFIG.M4, find the following
DNL If your extension references something external, use with:
..
DNL otherwise use enable:
..
This is where you choose your extension to use with or enable, we use with bar. Uncomment the WITH section.
If you use the Vim editor as much as I do, it's easy to see that the three-letter dnl is originally annotated (this is because VIM defaults to a syntax coloring package with various file formats)
After we modified the CONFIG.M4, we continued
Phpize
/configure
Make
At this point, the hello.so and hello.la files are generated under modules. One is a dynamic library, the other is a static library.
Your PHP extension has been done, although it has not yet achieved the functionality you want, let me first say how to use this extension! Ext_skel for you to generate a hello.php inside a call example, but that example requires you to copy the hello.so to PHP's extended directory, we just want to achieve their own functions, do not want to build a cottage version of PHP, use my following method to load it:
Copy Code code as follows:
if (!extension_loaded ("Hello")) {
Dl_local ("hello.so");
}
function Dl_local ($extensionFile) {
Make sure so 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 extensions can go with your PHP code and grow green.
The next concern is how to add functions, implement parameter passing, and return values
Add function steps as follows:
Php_hello.h:
Php_function (confirm_hello_compiled);//parentheses fill in the name of the letter
hello.c
Zend_function_entry hello_functions[] = {
Php_fe (confirm_hello_compiled, NULL)/* Add one line here * *
{null, NULL, NULL}/* must is the last line in hello_functions[] * *
};
Php_function (confirm_hello_compiled)
{//Here Write function body
}
The function prototype to be implemented is actually the same, with a macro php_function to wrap it up, and, in addition, add a line of information in the hello_functions, which means that you have this function in this module.
So are all the same function prototypes, how do you differentiate between return values and parameters?
I give an example:
Copy Code code 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--;
m--;
}
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 +) {
if (r1[i-1] = = R2[j-1]) cost = 0;
else cost = 1;
int a = MIN (d[i-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]);
}
This is a two-string difference degree algorithm, input parameters two string, return integer.
Transfer of parameters look here
Zend_parse_parameters (Zend_num_args () TSRMLS_CC, "SS", &r1, &n, &R2, &m)
Take this as a scanf to understand.
The type description is shown in the following table:
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* |
If you want to implement optional parameters, such as a string, a floating-point, and an optional bool type, you can use "sd|b" to represent it.
What's different with scanf is that for strings, you provide two variables to store, one is char *, the address of the stored string, an int, to keep the length of the string. When this is necessary, you can safely handle binary data.
So what about the return value?
Use the following set of macros to represent:
Return_string
Return_long
Return_double
Return_bool
Return_null
Note that return_string has two parameters
When you need to copy a string, use the
Return_string ("Hello World", 1);
otherwise use
Return_string (str, 0);
This involves the allocation of memory in the module, when you request the memory needs of the PHP program to release, please refer to the following table
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) |
In general, we use these non-persistent in the list.
Basically, you can start writing a php extension.
From my current application, the ability to manipulate strings is enough, so I can only introduce so much.