1, written in the first With the rapid development of the Internet, the popularity of lamp architecture, the expansion of PHP support is more and more, so that directly promote the development of PHP. But PHP also has the inevitable problem of scripting language, performance than for example, C and other compiled language is very different, so in the consideration of performance issues, it is best to use the PHP extension to solve. So, how to do a php extension it. Let's start with an example (this article requires C-base). 2, solve a problem In a system, if you frequently ask for the sum of squares of an array, we can write this.
- function Array_square_sum ($data) {
- $sum = 0;
- foreach ($data as $value) {
- $sum + = $value * $value;
- }
- return $sum;
- }
Copy CodeWhen actually executed, the PHP Zend engine translates the phrase into C, which requires memory allocation every time. So the performance is relatively poor. And then, based on performance considerations, we can write an extension to do this thing. 3. Write the extension Build an extension that requires a minimum of 2 files. One is the Configulator file, which tells the compiler to compile at least which dependent libraries are required for the extension, and the second is the actual executable file. 3.1 Build Framework It sounds complicated, and there's actually a tool that can help us with an extended framework. In the PHP source code there is a tool Ext_skel, he can help us build the extension framework.
- liujun@ubuntu:~/test/php-5.5.8/ext$ ls Ext_skel
- Ext_skel
Copy CodeNow we use it to generate the extension array_square_sum. ($ = prompt command)
- $./ext_skel--extname=array_square_sum
- Creating directory array_square_sum
- Creating basic F Iles:config.m4 config.w32. Svnignore array_square_sum.c php_array_square_sum.h CREDITS experimental TESTS/001.PHPT array_square_sum.php [done].
-
- To use your new extension, and you'll have to execute the following steps:
-
- 1. $ CD.
- 2. $ vi ext/array_square_sum/config.m4
- 3. $./buildconf
- 4. $./configure--[with|enable]-ar Ray_square_sum
- 5. $ make
- 6. $./php-f ext/array_square_sum/array_square_sum.php
- 7. $ VI Ext /ARRAY_SQUARE_SUM/ARRAY_SQUARE_SUM.C
- 8. $ make
-
- Repeat steps 3-6 until your is satisfied wit H ext/array_square_sum/config.m4 and
- Step 6 confirms that your module was compiled into PHP. Then, start writing
- code and repeat the last of the steps as often as necessary.
Copy CodeAfter executing the command, the terminal tells us how to produce a new extension. Look at the contents of the file, you will find a few more important documents CONFIG.M4, PHP_ARRAY_SQUARE_SUM.H,ARRAY_SQUARE_SUM.C, the following will be described.
- liujun@ubuntu:~/test/php-5.5.8/ext$ ll array_square_sum/
- Total 44
- Drwxr-xr-x 3 Liujun liujun 4096 Jan 29 15:40./
- Drwxr-xr-x Liujun Liujun 4096 Jan 29 15:40.. /
- -rw-r--r--1 Liujun liujun 5548 Jan 15:40 array_square_sum.c
- -rw-r--r--1 Liujun liujun 532 Jan 15:40 array_square_sum.php
- -rw-r--r--1 Liujun liujun 2354 Jan 15:40 config.m4
- -rw-r--r--1 Liujun liujun 366 Jan 15:40 Config.w32
- -rw-r--r--1 Liujun Liujun 15:40 CREDITS
- -rw-r--r--1 liujun liujun 0 Jan 15:40 Experimental
- -rw-r--r--1 Liujun liujun 3112 Jan 15:40 php_array_square_sum.h
- -rw-r--r--1 Liujun liujun 15:40. Svnignore
- Drwxr-xr-x 2 Liujun liujun 4096 Jan 15:40 tests/
Copy Code3.2 Configuration file Config.m4
- DNL Php_arg_with (array_square_sum, for array_square_sum support,
- DNL Make sure, the comment is aligned:
- DNL [--with-array_square_sum Include array_square_sum support])
Copy CodeRemove DNL
- Php_arg_with (Array_square_sum, for array_square_sum support,
- Make sure, the comment is aligned:
- [--with-array_square_sum Include array_square_sum support])
Copy CodeThis is the minimum requirement to be able to invoke the Enable-sample option when/configure. The second parameter of the php_arg_enable is displayed when the configuration file for this extension is reached during the./configure process. The third parameter is displayed as a help message when the end user executes the./configure--help. 3.3 Header Files Modify Php_array_square_sum.h, change the confirm_array_square_sum_compiled to Confirm_array_square_sum, this is the function name that we actually call later, Of course you can also directly join the function confirm_array_square_sum without deleting confirm_array_square_sum_compiled.
- Php_function (confirm_array_square_sum_compiled);
Copy CodeIt becomes
- Php_function (array_square_sum);
Copy Code3.3 Source Code Modify the ARRAY_SQUARE_SUM.C, change the confirm_array_square_sum_compiled to Confirm_array_square_sum, this is the function that registers this extension, If you join Confirm_array_square_sum directly in 3.2, you can also join Confirm_array_square_sum directly in this step.
- Const Zend_function_entry array_square_sum_functions[] = {
- Php_fe (confirm_array_square_sum_compiled, NULL)/* For testing, remove later. */
- Php_fe_end/* Must be the last line in array_square_sum_functions[] */
- };
Copy CodeChange into
- Const Zend_function_entry array_square_sum_functions[] = {
- Php_fe (Array_square_sum, NULL)/* For testing, remove later. */
- Php_fe_end/* Must be the last line in array_square_sum_functions[] */
- };
Copy CodeThen one of the most critical steps to rewrite the confirm_array_square_sum is to rewrite the confirm_array_square_sum_compiled into Confirm_array_square_sum ( 3.1 did not delete confirm_array_square_sum_compiled, you need to join confirm_array_square_sum just fine).
- Php_function (confirm_array_square_sum_compiled)
Copy CodeRewritten as
- Php_function (Array_square_sum)
- {
- zval* Array_data;
- HashTable *ht_data;
- int ret;
- char* key;
- UINT Index;
- Zval **pdata;
- Double sum = 0;
- if (Zend_parse_parameters (Zend_num_args () tsrmls_cc, "a", &array_data) = = FAILURE) {
- Return
- }
- Ht_data = Z_arrval_p (Array_data);
- Zend_hash_internal_pointer_reset (Ht_data);
- while (hash_key_non_existant! = (ret = Zend_hash_get_current_key (Ht_data, &key, &index, 0))) {
- ret = Zend_hash_get_current_data (Ht_data, &pdata);
- if (z_type_p (*pdata) = = Is_long) {
- Sum + = z_lval_p (*pdata) * z_lval_p (*pdata);
- }else {
- Return_false;
- }
- Zend_hash_move_forward (Ht_data);
- }
- Zend_hash_internal_pointer_end (Z_arrval_p (array_data));
- Retval_double (sum);
- }
Copy CodePHP is a weakly typed language, and all of his data exists in the structure zval (see More specialized materials such as "PHP Extensions development. PDF").
- typedef Union _ZVAL {
- Long lval;
- Double Dval;
- struct {
- Char *val;
- int Len;
- } str;
- HashTable *ht;
- Zend_object_value obj;
- } Zval;
Copy CodeTo get the arguments passed by the function, you can use the Zend_parse_parameters () API function. Here is the prototype of the function:
- zend_parse_parameters (int num_args tsrmls_dc, char *type_spec, ...);
Copy Code The first few parameters of the zend_parse_parameters () function can be generated directly from the kernel macro, in the form: Zend_num_args () TSRMLS_CC, note that there is a space between the two, but there is no comma. As you can see from the name, Zend_num_args () represents the number of this parameter. The following is a common parameter type (similar to the C-language printf) followed by a common list of parameters. The following table lists the common parameter types.
Parameter type |
Object C type |
Description |
L |
Long |
Integer |
B |
bool |
Boolean |
S |
char* |
String |
D |
Double |
Floating point number |
A |
Array (zval*) |
Array |
Z |
zval* |
Uncertainty Zval |
The array is also a large hashtable to implement, so zend_hash_get_current_key can iterate through the array, using the macro z_lval_p (zval*) to get the actual value. You can finally put the results into sum. Retval_double (value) is also a macro that returns a DOUBLE with a value of values, as described in " PHP extension development. pdf".
Finally, the development of this main function is completed. 3.4 Generating Configure Files Then execute ~/php/bin/phpize
- /home/liujun/php/bin/phpize
Copy Code
- Configuring for:
- PHP Api version:20121113
- Zend Module Api no:20121212
- Zend Extension Api no:220121212
Copy Code
You can see that the executable script configure appears in Array_square_sum. 3.5 compiling It is best to take php-config path when compiling, because the default php-config-path of the system may not be the PHP path you are currently using.
- liujun@ubuntu:~/test/php-5.5.8/ext/array_square_sum$./configure--with-php-config=/home/liujun/php/bin/ Php-config
Copy CodeIf the compilation succeeds, the terminal will have the following prompt:
- Creating Libtool
- Appending configuration Tag "CXX" to Libtool
- Configure:creating./config.status
- Config.status:creating config.h
- Config.status:config.h is unchanged
Copy CodeLooking at the module directory of the Array_square_sum directory, you will find the build array_square_sum.so inside, this is the extension we need.
- liujun@ubuntu:~/test/php-5.5.8/ext/array_square_sum$ ls modules/
- Array_square_sum.la array_square_sum.so
Copy Code4. Using extensions 4.1. Configuration extension Modify the configuration of PHP php.ini, add the configuration content.
- [Array_square_sum]
- Extension=array_square_sum.so
Copy Code4.2. Add Module PHP extension generally in the $PHP _PATH/LIB/PHP/EXTENSIONS/NO-DEBUG-NON-ZTS-YYYYMMDD, if not found, please Baidu or Google itself. There are many. so files in it. A copy of the 3.5 production array_sum_square.so can be made. If you use fastcgi mode, you need to restart PHP, so that we should have an extension of Php array_square_sum, the specific can be viewed phpinfo (not please Baidu Orgoogle). 4.2. Write code Since writing an extension can improve operational efficiency, here we test performance by using extensions and using PHP code directly for comparison. Multiple experiments can reduce the error, so 2000 times to 100,000 numbers squared sum. The code is as follows:
- $data = Array ();
- $max _index = 100000;
- $test _time = 2000;
- for ($i =0; $i < $max _index; $i + +) {
- $data [] = $i;
- }
- $php _test_time_start = time ();
- Php_test ($test _time, $data);
- $php _test_time_stop = time ();
- echo "PHP Test ext time is". ($php _test_time_stop-$php _test_time_start). "\ n";
- $c _test_time_start = time ();
- C_test ($test _time, $data);
- $c _test_time_stop = time ();
- echo "PHP test time is". ($c _test_time_stop-$c _test_time_start). "\ n";
- function Php_test ($test _time, $test _data) {
- for ($i =0; $i < $test _time; $i + +) {
- $sum = 0;
- foreach ($test _data as $data) {
- $sum + = $data * $DATA;
- }
- }
- }
- function C_test ($test _time, $test _data) {
- for ($i =0; $i < $test _time; $i + +) {
- $sum = Array_square_sum ($test _data);
- }
- }
Copy CodeThe test results are as follows:
- liujun@ubuntu:~/php$ ~/php/bin/php test.php
- PHP Test ext Time is 30
- PHP Test Time is 2
Copy Code You can see that the extension is 15 times times faster than using PHP directly. As business logic becomes more complex, the difference will be greater. Then use the C language directly to do this thing. The following also gives a code to test under (the test conditions are exactly the same):
- #include
- #include
- #include
- #define TEST_TIME 2000
- #define MAX_INDEX 100000
- int main ()
- {
- int Data[max_index];
- Double sum = 0;
- for (int i=0; i
- Data[i] = i;
- }
- struct Timeval start;
- struct Timeval end;
- Gettimeofday (&start,null);
- for (int i=0; i
- for (int j=0; j
- Sum + = data[j] * Data[j];
- }
- }
- Gettimeofday (&end,null);
- Double Time= (end.tv_sec-start.tv_sec) + (end.tv_usec-start.tv_usec) * 1.0/1000000;
- printf ("Total time is%lf\n", time);
- printf ("Sum time is%lf\n", sum);
- return 0;
- }
Copy CodeTo perform the viewing effect, you can see that the direct use of C is only 0.261746 of the time, is using the C extension of 13.09%, is directly using PHP 0.87%. Of course, if it involves complex operations such as IO, C + + will be tens of thousands of times faster than PHP (tested).
- liujun@ubuntu:~/php$ g++ test.cpp-o2-o Test
- liujun@ubuntu:~/php$./test
- Total time is 0.261746
- Sum time is 36207007178615872.000000
Copy Code Therefore, in the actual performance requirements of very high services, such as indexing, word breakers, etc., you can use C to do a set of low-level services, PHP to make encapsulation calls. |