Step-by-step preparation of PHP extensions

Source: Internet
Author: User
Tags configuration php
Step-by-step preparation of PHP extensions
1. Preface

With the rapid development of the Internet and the prevalence of lamp architecture, php supports more and more extensions, which directly promotes the development of php.

However, php also has an inevitable problem with the scripting language. There are many differences in the performance ratio, such as C, among other compiled languages. Therefore, it is best to use php extension to solve the problem of performance.

So, how to make a php extension. The following is an example (C basics are required in this article ).

2. solve a problem

In a system, if the sum of squares of an array is often required, we can write it like this.

  1. Function array_square_sum ($ data ){
  2. $ Sum = 0;
  3. Foreach ($ data as $ value ){
  4. $ Sum + = $ value * $ value;
  5. }
  6. Return $ sum;
  7. }

During actual execution, the php zend Engine translates this passage into a C language, and memory allocation is required each time. Therefore, the performance is poor. Furthermore, based on performance considerations, we can write an extension to do this.

3. write extensions

Building an extension requires at least two files. One is the Configulator file, which will tell the compiler which dependent libraries are required to compile this extension at least, and the second is the actually executed file.

3.1 generate framework

It sounds complicated. In fact, there is a tool that can help us deal with an extended framework. There is an ext_skel tool in the php source code, which can help us generate an extension framework.

  1. Liujun @ ubuntu :~ /Test/php-5.5.8/ext $ ls ext_skel
  2. Ext_skel

Now we use it to generate the extended array_square_sum. ($ Indicates the prompt command)

  1. $./Ext_skel -- extname = array_square_sum
  2. Creating directory array_square_sum
  3. Creating basic files: config. m4 config. w32. svnignore array_square_sum.c php_array_square_sum.h credits experimental tests/001. phpt array_square_sum.php [done].
  4. To use your new extension, you will have to execute the following steps:
  5. 1. $ cd ..
  6. 2. $ vi ext/array_square_sum/config. m4
  7. 3. $./buildconf
  8. 4. $./configure -- [with | enable]-array_square_sum
  9. 5. $ make
  10. 6. $./php-f ext/array_square_sum/array_square_sum.php
  11. 7. $ vi ext/array_square_sum/array_square_sum.c
  12. 8. $ make
  13. Repeat steps 3-6 until you are satisfied with ext/array_square_sum/config. m4 and
  14. Step 6 confirms that your module is compiled into PHP. Then, start writing
  15. Code and repeat the last two steps as often as necessary.

After executing the command, the terminal tells us how to produce new extensions. Check the file content and find several more important files: config. m4, php_array_square_sum.h, and array_square_sum.c.

  1. Liujun @ ubuntu :~ /Test/php-5.5.8/ext $ ll array_square_sum/
  2. Total 44
  3. Drwxr-xr-x 3 liujun 4096 Jan 29 :40 ./
  4. Drwxr-xr-x 80 liujun 4096 Jan 29 ../
  5. -Rw-r -- 1 liujun 5548 Jan 29 array_square_sum.c
  6. -Rw-r -- 1 liujun 532 Jan 29 array_square_sum.php
  7. -Rw-r -- 1 liujun 2354 Jan 29 config. m4
  8. -Rw-r -- 1 liujun 366 Jan 29 config. w32
  9. -Rw-r -- 1 liujun 16 Jan 29 :40 CREDITS
  10. -Rw-r -- 1 liujun 0 Jan 29 15:40 EXPERIMENTAL
  11. -Rw-r -- 1 liujun 3112 Jan 29 php_array_square_sum.h
  12. -Rw-r -- 1 liujun 16 Jan 29 :40. svnignore
  13. Drwxr-xr-x 2 liujun 4096 Jan 29 tests/

3.2 configuration file config. m4

  1. Dnl PHP_ARG_WITH (array_square_sum, for array_square_sum support,
  2. Dnl Make sure that the comment is aligned:
  3. Dnl [-- with-array_square_sum Include array_square_sum support])

Remove dnl

  1. PHP_ARG_WITH (array_square_sum, for array_square_sum support,
  2. Make sure that the comment is aligned:
  3. [-- With-array_square_sum Include array_square_sum support])

This is. /The minimum requirement for the enable-sample option to be called during configure. the second parameter of PHP_ARG_ENABLE will be in. /displayed when the extended configuration file is reached during configure processing. the third parameter will be executed by the end user. /configure -- help is displayed as help information

3.3 header files

Modify php_array_square_sum.h, and change role to confirm_array_square_sum. this is the name of the function actually called in the future. of course, you can add the function confirm_array_square_sum without deleting the role.

  1. PHP_FUNCTION (confirm_array_square_sum_compiled );

The

  1. PHP_FUNCTION (array_square_sum );

Source code 3.3

Modify array_square_sum.c, and change sums to confirm_array_square_sum. this is the function for registering this extension. if The struct is directly added to 3.2, you can add confirm_array_square_sum in this step.

  1. Const zend_function_entry array_square_sum_functions [] = {
  2. PHP_FE (confirm_array_square_sum_compiled, NULL)/* For testing, remove later .*/
  3. PHP_FE_END/* Must be the last line in array_square_sum_functions [] */
  4. };

Change

  1. Const zend_function_entry array_square_sum_functions [] = {
  2. PHP_FE (array_square_sum, NULL)/* For testing, remove later .*/
  3. PHP_FE_END/* Must be the last line in array_square_sum_functions [] */
  4. };

Then, rewrite confirm_array_square_sum in the most critical step. in this case, you only need to rewrite the statement to confirm_array_square_sum (the statement is not deleted in 3.1, so you need to add confirm_array_square_sum ).

  1. PHP_FUNCTION (confirm_array_square_sum_compiled)

Rewrite

  1. PHP_FUNCTION (array_square_sum)
  2. {
  3. Zval * array_data;
  4. HashTable * ht_data;
  5. Int ret;
  6. Char * key;
  7. Uint index;
  8. Zval ** pdata;
  9. Double sum = 0;
  10. If (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, "a", & array_data) = FAILURE ){
  11. Return;
  12. }
  13. Ht_data = Z_ARRVAL_P (array_data );
  14. Zend_hash_internal_pointer_reset (ht_data );
  15. While (HASH_KEY_NON_EXISTANT! = (Ret = zend_hash_get_current_key (ht_data, & key, & index, 0 ))){
  16. Ret = zend_hash_get_current_data (ht_data, & pdata );
  17. If (Z_TYPE_P (* pdata) = IS_LONG ){
  18. Sum + = Z_LVAL_P (* pdata) * Z_LVAL_P (* pdata );
  19. } Else {
  20. RETURN_FALSE;
  21. }
  22. Zend_hash_move_forward (ht_data );
  23. }
  24. Zend_hash_internal_pointer_end (Z_ARRVAL_P (array_data ));
  25. RETVAL_DOUBLE (sum );
  26. }

Php is a weak language, and its data is stored in the zval structure (for details, see more professional materials, such as "phpextended development pipeline ").

  1. Typedef union _ zval {
  2. Long lval;
  3. Double dval;
  4. Struct {
  5. Char * val;
  6. Int len;
  7. } Str;
  8. HashTable * ht;
  9. Zend_object_value obj;
  10. } Zval;

To obtain the parameters passed by the function, you can use the zend_parse_parameters () API function. The following is a prototype of the function:

  1. Zend_parse_parameters (int num_args TSRMLS_DC, char * type_spec ,...);

The first few parameters of the zend_parse_parameters () function can be directly generated using the macro in the kernel. the format is ZEND_NUM_ARGS () TSRMLS_CC. Note that there is a space between the two, but there is no comma. It can be seen from the name that ZEND_NUM_ARGS () represents the number of this parameter. Followed by a common parameter type (similar to the C language printf), followed by a list of common parameters.
The following table lists 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


In addition, the array is implemented by a large hashtable, so zend_hash_get_current_key can traverse the array and use the macro Z_LVAL_P (zval *) to obtain the actual value. Finally, you can put the result into sum. RETVAL_DOUBLE (value) is also a macro. the returned result is double and the value is value. for details, see "phpextended development detail ".

Finally, the development of the main function is completed.

3.4 generate the configure file

Then execute ~ /Php/bin/phpize

  1. /Home/liujun/php/bin/phpize

  1. Processing ING:
  2. PHP Api Version: 20121113
  3. Zend Module Api No: 20121212
  4. Zend Extension Api No: 220121212


It can be found that the executable script configure appears in array_square_sum.

3.5 Compile

It is best to include the php-config PATH when compiling, because the default php-config-path in the system may not be your current php PATH.

  1. Liujun @ ubuntu :~ /Test/php-5.5.8/ext/array_square_sum $./configure -- with-php-config =/home/liujun/php/bin/php-config

If the compilation is successful, the terminal will prompt as follows:

  1. Creating libtool
  2. Appending configuration tag "CXX" to libtool
  3. Configure: creating./config. status
  4. Config. status: creating config. h
  5. Config. status: config. h is unchanged

View the module directory of the array_square_sum directory and you will find that array_square_sum.so is generated in it. this is the extension we need.

  1. Liujun @ ubuntu :~ /Test/php-5.5.8/ext/array_square_sum $ ls modules/
  2. Array_square_sum.la array_square_sum.so

4. use extension 4.1 and configuration extension

Modify the php configuration php. ini and add the configuration content.

  1. [Array_square_sum]
  2. Extension = array_square_sum.so

4.2 Add module

Php extensions are generally found in $ PHP_PATH/lib/php/extensions/no-debug-non-zts-yyyymmdd. if you cannot find them, baidu or Google. there are many. so file.

Copy array_sum_square.so produced in 3.5.

If fastcgi mode is used, restart php. in this case, we should have extended array_square_sum in php. for details, see phpinfo (not Baidu orGoogle ).

4.2 Write code

Since writing extensions can improve the running efficiency, here we use extensions and directly use php code to compare and test the performance. Multiple experiments can reduce the error. Therefore, 2000 times are performed to calculate the sum of squares of the 100000 numbers. The code is as follows:

  1. $ Data = array ();
  2. $ Max_index = 100000;
  3. $ Test_time = 2000;
  4. For ($ I = 0; $ I <$ max_index; $ I ++ ){
  5. $ Data [] = $ I;
  6. }
  7. $ Php_test_time_start = time ();
  8. Php_test ($ test_time, $ data );
  9. $ Php_test_time_stop = time ();
  10. Echo "php test ext time is". ($ php_test_time_stop-$ php_test_time_start). "\ n ";
  11. $ C_test_time_start = time ();
  12. C_test ($ test_time, $ data );
  13. $ C_test_time_stop = time ();
  14. Echo "php test time is". ($ c_test_time_stop-$ c_test_time_start). "\ n ";
  15. Function php_test ($ test_time, $ test_data ){
  16. For ($ I = 0; $ I <$ test_time; $ I ++ ){
  17. $ Sum = 0;
  18. Foreach ($ test_data as $ data ){
  19. $ Sum + = $ data * $ data;
  20. }
  21. }
  22. }
  23. Function c_test ($ test_time, $ test_data ){
  24. For ($ I = 0; $ I <$ test_time; $ I ++ ){
  25. $ Sum = array_square_sum ($ test_data );
  26. }
  27. }

The test results are as follows:

  1. Liujun @ ubuntu :~ /Php $ ~ /Php/bin/php test. php
  2. Php test ext time is 30
  3. Php test time is 2

It can be seen that the extension is 15 times faster than using php directly. As the business logic becomes more complex, the difference will increase.

Then we can directly use the C language to do this. The following code is also provided for testing (the test conditions are exactly the same ):

  1. # Include
  2. # Include
  3. # Include
  4. # Define TEST_TIME 2000
  5. # Define MAX_INDEX 100000
  6. Int main ()
  7. {
  8. Int data [MAX_INDEX];
  9. Double sum = 0;
  10. For (int I = 0; I Data [I] = I;
  11. }
  12. Struct timeval start;
  13. Struct timeval end;
  14. Gettimeofday (& start, NULL );
  15. For (int I = 0; I For (int j = 0; j Sum + = data [j] * data [j];
  16. }
  17. }
  18. Gettimeofday (& end, NULL );
  19. Double time = (end. TV _sec-start. TV _sec) + (end. TV _usec-start. TV _usec) * 1.0/1000000;
  20. Printf ("total time is % lf \ n", time );
  21. Printf ("sum time is % lf \ n", sum );
  22. Return 0;
  23. }

Run the command to check the effect. it can be seen that the time to directly use C is only 0.261746, which is 13.09% of the C extension and 0.87% of php. Of course, if complicated operations such as I/O are involved, C/C ++ will be ten thousand times faster than php (tested ).

  1. Liujun @ ubuntu :~ /Php $ g ++ test. cpp-O2-o test
  2. Liujun @ ubuntu :~ /Php $./test
  3. Total time is 0.261746
  4. Sum time is 36207007178615872.000000

Therefore, in actual services that have high performance requirements, such as indexing and word segmentation, you can use C for a set of underlying services and php for encapsulation and calling.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.