Get started writing PHP extensions in one step

Source: Internet
Author: User
Tags php source code

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.

    1. function Array_square_sum ($data) {
    2. $sum = 0;
    3. foreach ($data as $value) {
    4. $sum + = $value * $value;
    5. }
    6. return $sum;
    7. }
Copy Code

When 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.

    1. liujun@ubuntu:~/test/php-5.5.8/ext$ ls Ext_skel
    2. Ext_skel
Copy Code

Now we use it to generate the extension array_square_sum. ($ = prompt command)

    1. $./ext_skel--extname=array_square_sum
    2. Creating directory array_square_sum
    3. 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].
    4. To use your new extension, and you'll 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]-ar Ray_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 your is satisfied wit H ext/array_square_sum/config.m4 and
    14. Step 6 confirms that your module was compiled into PHP. Then, start writing
    15. code and repeat the last of the steps as often as necessary.
Copy Code

After 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.

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

3.2 Configuration file Config.m4

    1. DNL Php_arg_with (array_square_sum, for array_square_sum support,
    2. DNL Make sure, the comment is aligned:
    3. DNL [--with-array_square_sum Include array_square_sum support])
Copy Code

Remove DNL

    1. Php_arg_with (Array_square_sum, for array_square_sum support,
    2. Make sure, the comment is aligned:
    3. [--with-array_square_sum Include array_square_sum support])
Copy Code

This 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.

    1. Php_function (confirm_array_square_sum_compiled);
Copy Code

It becomes

    1. Php_function (array_square_sum);
Copy Code

3.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.

    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. };
Copy Code

Change into

    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. };
Copy Code

Then 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).

    1. Php_function (confirm_array_square_sum_compiled)
Copy Code

Rewritten as

  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. }
Copy Code

PHP 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").

    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;
Copy Code

To get the arguments passed by the function, you can use the Zend_parse_parameters () API function. Here is the prototype of the function:

    1. 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

    1. /home/liujun/php/bin/phpize
Copy Code

    1. Configuring for:
    2. PHP Api version:20121113
    3. Zend Module Api no:20121212
    4. 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.

    1. liujun@ubuntu:~/test/php-5.5.8/ext/array_square_sum$./configure--with-php-config=/home/liujun/php/bin/ Php-config
Copy Code

If the compilation succeeds, the terminal will have the following prompt:

    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
Copy Code

Looking 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.

    1. liujun@ubuntu:~/test/php-5.5.8/ext/array_square_sum$ ls modules/
    2. Array_square_sum.la array_square_sum.so
Copy Code

4. Using extensions

4.1. Configuration extension

Modify the configuration of PHP php.ini, add the configuration content.

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

4.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:

  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. }
Copy Code

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
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):

  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
  11. Data[i] = i;
  12. }
  13. struct Timeval start;
  14. struct Timeval end;
  15. Gettimeofday (&start,null);
  16. for (int i=0; i
  17. for (int j=0; j
  18. Sum + = data[j] * Data[j];
  19. }
  20. }
  21. Gettimeofday (&end,null);
  22. Double Time= (end.tv_sec-start.tv_sec) + (end.tv_usec-start.tv_usec) * 1.0/1000000;
  23. printf ("Total time is%lf\n", time);
  24. printf ("Sum time is%lf\n", sum);
  25. return 0;
  26. }
Copy Code

To 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).

    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
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.

  • Related Article

    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.