>백엔드 개발 >PHP 튜토리얼 >PHP 확장 작성을 위한 단계별 가이드

PHP 확장 작성을 위한 단계별 가이드

WBOY
WBOY원래의
2016-07-25 09:12:321017검색

1. 먼저 작성하세요

인터넷의 급속한 발전과 램프 아키텍처의 인기로 인해 PHP는 점점 더 많은 확장 기능을 지원하며 이는 PHP 개발을 직접적으로 촉진합니다.

그러나 PHP 역시 스크립팅 언어에서는 피할 수 없는 문제가 있습니다. C 등의 컴파일 언어와는 성능이 많이 다르기 때문에 성능 문제를 고려할 때는 PHP 확장을 통해 해결하는 것이 가장 좋습니다.

그럼, PHP 확장을 만드는 방법은 다음과 같습니다. 예제부터 시작해 보겠습니다(이 문서에는 C 기본 사항이 필요합니다).

2. 문제 해결

시스템에서 배열의 제곱합이 자주 필요한 경우 다음과 같이 작성할 수 있습니다.

  1. 함수 array_square_sum($data){
  2. $sum = 0;
  3. foreach($data를 $value로){
  4. $sum = $value * $value;
  5. }
  6. return $sum;
  7. }
실제 실행 시 코드 복사

, PHP Zend 엔진은 이 구절을 C 언어로 번역하며, 매번 메모리 할당이 필요합니다. 그래서 성능이 상대적으로 안좋습니다. 또한 성능 고려 사항을 기반으로 이를 수행하기 위한 확장을 작성할 수 있습니다.

3. 확장 프로그램 작성

확장 프로그램을 빌드하려면 최소 2개의 파일이 필요합니다. 하나는 이 확장을 컴파일하는 데 필요한 최소한 종속 라이브러리를 컴파일러에 알려주는 구성 파일입니다. 두 번째는 실제 실행 파일입니다.

3.1 프레임워크 생성

복잡해 보이지만 실제로는 확장된 프레임워크를 얻는 데 도움이 되는 도구가 있습니다. PHP 소스 코드에는 확장 프레임워크를 생성하는 데 도움이 되는 ext_skel 도구가 있습니다.

  1. liujun@ubuntu:~/test/php-5.5.8/ext$ ls ext_skel
  2. ext_skel
코드 복사

이제 이를 사용하여 확장된 array_square_sum을 생성합니다. ($는 프롬프트 명령을 나타냅니다)

  1. $ ./ext_skel --extname=array_square_sum
  2. array_square_sum 디렉토리 생성
  3. 기본 파일 생성: config.m4 config.w32 . svnignore array_square_sum.c php_array_square_sum.h 크레딧 실험 테스트/001.phpt array_square_sum.php [done].
  4. 새 확장 기능을 사용하려면 다음 단계를 실행해야 합니다:
  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. 3단계를 반복하세요. -6 ext/array_square_sum/config.m4에 만족할 때까지
  13. 6단계에서 모듈이 PHP로 컴파일되었는지 확인한 다음
  14. 코드 작성을 시작하고 필요한 만큼 마지막 두 단계를 반복하세요.
코드 복사
명령을 실행한 후 터미널에서는 새로운 확장 프로그램을 생성하는 방법을 알려줍니다. 파일 내용을 확인하면 config.m4, php_array_square_sum.h, array_square_sum.c와 같은 몇 가지 중요한 파일이 있다는 것을 알 수 있습니다. 이에 대해서는 아래에서 하나씩 설명하겠습니다.

liujun@ubuntu:~/test/php-5.5.8/ext$ ll array_square_sum/
    총 44
  1. drwxr-xr-x 3 liujun liujun 4096 1월 29일 15:40 ./
  2. drwxr-xr-x 80 liujun liujun 4096 1월 29일 15:40 ../
  3. -rw-r--r-- 1 liujun liujun 5548 1월 29일 15:40 array_square_sum .c
  4. -rw-r--r-- 1 liujun liujun 532 1월 29일 15:40 array_square_sum.php
  5. -rw-r--r-- 1 liujun liujun 2354 1월 29일 15:40 config.m4
  6. -rw-r--r-- 1 liujun liujun 366 1월 29일 15:40 config.w32
  7. -rw-r--r-- 1 liujun liujun 1월 29일 15:40 크레딧
  8. - rw-r--r-- 1 liujun liujun 0 1월 29일 15:40 실험
  9. -rw-r--r-- 1 liujun liujun 3112 1월 29일 15:40 php_array_square_sum.h
  10. -rw-r- -r-- 1 liujun liujun 1월 16일 15:40 .svnignore
  11. drwxr-xr-x 2 liujun liujun 4096 1월 29일 15:40 테스트/
코드 복사

3.2 구성 파일 config.m4

dnl PHP_ARG_WITH(array_square_sum, array_square_sum 지원용,
    dnl 주석이 정렬되었는지 확인하세요.
  1. dnl [ --with-array_square_sum array_square_sum 지원 포함])
코드 복사

dnl 제거

PHP_ARG_WITH(array_square_sum, array_square_sum 지원의 경우,
    주석이 정렬되었는지 확인하세요.
  1. [ --with-array_square_sum array_square_sum 포함 지원])
코드 복사

이는 ./configure 시 활성화 샘플 옵션을 호출할 수 있는 최소 요구 사항입니다. ./configure 처리 중에 이 확장 구성 파일에 도달하면 PHP_ARG_ENABLE의 두 번째 매개 변수가 표시됩니다. 최종 사용자에 의해 ./configure --help

실행 시 도움말 정보로 표시됩니다.

3.3 헤더 파일

php_array_square_sum.h를 수정하고,confirm_array_square_sum_compiled를 verify_array_square_sum으로 변경합니다. 이는 앞으로 우리가 실제로 호출할 함수의 이름입니다. 물론, verify_array_square_sum_compiled를 삭제하지 않고, verify_array_square_sum 함수를 직접 추가할 수도 있습니다.

  1. PHP_FUNCTION(confirm_array_square_sum_compiled);
코드 복사

해야 합니다

  1. PHP_FUNCTION(array_square_sum);
코드 복사

3.3 소스코드

array_square_sum.c를 수정하고 verify_array_square_sum_compiled를 verify_array_square_sum으로 변경합니다. 이 확장자를 등록하는 함수입니다. 3.2에서confirm_array_square_sum을 직접 추가했다면 이 단계에서 직접 verify_array_square_sum을 추가하면 됩니다.

  1. const zend_function_entry array_square_sum_functions[] = {
  2. PHP_FE(confirm_array_square_sum_compiled, NULL) /* 테스트를 위해 나중에 제거하세요. */
  3. PHP_FE_END /* array_square_sum_functions[] */
  4. };
코드를 복사

하여

    로 변경하세요.
  1. const zend_function_entry array_square_sum_functions[] = {
  2. PHP_FE(array_square_sum, NULL) /* 테스트를 위해 나중에 제거하세요. */
  3. PHP_FE_END /* array_square_sum_functions[]의 마지막 줄이어야 합니다. */
  4. } ;
코드 복사

그러면 가장 중요한 단계는 verify_array_square_sum을 다시 작성하는 것입니다. 이때, verify_array_square_sum_compiled를 verify_array_square_sum으로 다시 작성하기만 하면 됩니다(confirm_array_square_sum_compiled는 3.1에서는 삭제되지 않았으므로 verify_array_square_sum을 추가해야 합니다).

  1. PHP_FUNCTION(confirm_array_square_sum_compiled)
코드 복사

  1. PHP_FUNCTION(array_square_sum)
  2. {
  3. zval* array_data;
  4. HashTable *ht_data;
  5. int ret;< 🎜으로 다시 작성됨 > char* key;
  6. 단위 인덱스;
  7. zval **pdata;
  8. double sum = 0;
  9. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array_data) = = 실패) {
  10. return;
  11. }
  12. ht_data = Z_ARRVAL_P(array_data);
  13. zend_hash_internal_pointer_reset(ht_data);
  14. while ( HASH_KEY_NON_EXISTANT != (ret = zend_hash_get_current_key(ht_ data,&key) , &index, 0)) ) {
  15. ret = zend_hash_get_current_data(ht_data, &pdata);
  16. if( Z_TYPE_P(*pdata) == IS_LONG){
  17. sum = Z_LVAL_P(*pdata) * Z_LVAL_P (*pdata);
  18. }else {
  19. RETURN_FALSE;
  20. }
  21. zend_hash_move_forward(ht_data);
  22. }
  23. zend_hash_internal_pointer_end(Z_ARRVAL_P(array_data));
  24. RETVAL_DOUBLE(sum) ;
  25. }
코드 복사

PHP는 약한 유형의 언어이며 해당 데이터는 zval 구조에 저장됩니다. .

typedef Union _zval {

long lval;
double dval;
struct {
    char *val;
  1. int len;
  2. } str;
  3. HashTable *ht;
  4. zend_object_value obj;
  5. } zval;
  6. 코드 복사
함수가 전달한 매개변수를 얻으려면 zend_parse_parameters() API 함수를 사용할 수 있습니다. 다음은 함수의 프로토타입입니다.

zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, …);

코드 복사
  1. 커널의 매크로를 사용하여 zend_parse_parameters() 함수의 처음 몇 개의 매개변수를 직접 생성할 수 있습니다. 형식은 ZEND_NUM_ARGS() TSRMLS_CC입니다. 쉼표가 없습니다. 이름에서 알 수 있듯이 ZEND_NUM_ARGS()는 매개변수의 개수를 나타냅니다. 그 뒤에는 공통 매개변수 유형(C 언어의 printf와 유사)과 공통 매개변수 목록이 옵니다.
    다음 표에는 일반적인 매개변수 유형이 나열되어 있습니다.

    参数类型 对象C类型 说明
    l long 整数
    b bool 布尔
    s char* 字符串
    d double 浮点数
    a array(zval*) 数组
    z zval* 不确定性zval


    또한 배열은 대규모 해시 테이블로 구현되므로 zend_hash_get_current_key는 배열을 탐색하고 매크로 Z_LVAL_P(zval*)를 사용하여 실제 값을 얻을 수 있습니다. 마지막으로 결과를 합산할 수 있습니다. RETVAL_DOUBLE(값)도 매크로입니다. 반환 결과는 double이고 값은 value입니다. 자세한 내용은 "php 확장 개발.pdf"를 참조하세요.

    드디어 본 기능의 개발이 완료되었습니다.

    3.4 구성 파일 생성

    그런 다음 ~/php/bin/phpize를 실행합니다


      /home/liujun/php/bin/phpize
    코드 복사

      구성 대상:
    1. PHP Api 버전: 20121113
    2. Zend 모듈 Api 번호: 20121212
    3. Zend Extension Api 번호: 220121212
    코드 복사


    array_square_sum에 실행 가능한 스크립트 구성이 나타나는 것을 확인할 수 있습니다.

    3.5편찬

    시스템 기본 php-config-path가 현재 사용 중인 php 경로가 아닐 수 있으므로 컴파일할 때 php-config PATH를 가져오는 것이 가장 좋습니다.

      liujun@ubuntu:~/test/php-5.5.8/ext/array_square_sum$ ./configure --with-php-config=/home/liujun/php /bin/php-config
    코드 복사
    컴파일이 성공하면 터미널에 다음 프롬프트가 표시됩니다:

      libtool 생성
    1. libtool에 "CXX" 구성 태그 추가
    2. configure: ./config.status 생성
    3. config.status: config.h 생성
    4. config.status: config.h 변경되지 않았습니다
    코드 복사
    array_square_sum 디렉토리의 모듈 디렉토리를 확인하면 array_square_sum.so가 생성된 것을 확인할 수 있습니다. 이것이 우리에게 필요한 확장입니다. .

      liujun@ubuntu:~/test/php-5.5.8/ext/array_square_sum$ ls module/
    1. array_square_sum.la array_square_sum.so
    코드 복사

    4. 확장 프로그램 사용

    4.1. 구성 확장

    php 구성 php.ini를 수정하고 구성 내용을 추가합니다.

      [array_square_sum]
    1. extension=array_square_sum.so
    코드 복사

    4.2.모듈 추가

    PHP 확장은 일반적으로 $PHP_PATH/lib/php/extensions/no-debug-non-zts-yyyymmdd에 있습니다. 찾을 수 없으면 Baidu 또는 Google에 .so 파일이 많이 있습니다. .

    3.5에서 생성된 array_sum_square.so를 복사하면 됩니다.

    fastcgi 모드를 사용하는 경우 PHP를 다시 시작해야 하므로 PHP 확장자는 array_square_sum이어야 합니다. 자세한 내용은 phpinfo를 확인하세요. 알아요)

    4.2 코드 작성

    Extension을 작성하면 운영 효율성이 향상될 수 있으므로 여기서는 Extension을 사용하고 PHP 코드를 직접 사용하여 성능을 비교하고 테스트합니다. 여러 번 실험하면 오류를 줄일 수 있으므로 2,000번을 반복하여 100,000개의 숫자의 제곱의 합을 구하세요. 코드는 다음과 같습니다:

      $data = array();
    1. $max_index = 100000;
    2. $test_time = 2000 ;
    3. for($i=0; $i<$max_index; $i ){
    4. $data[] = $i
    5. }
    6. $php_test_time_start = time();
    7. php_test ($test_time, $data);
    8. $php_test_time_stop = time();
    9. echo "php 테스트 연장 시간은 "입니다. ($php_test_time_stop - $php_test_time_start);
    10. $c_test_time_start = time();
    11. c_test($test_time, $data);
    12. $c_test_time_stop = time();
    13. echo "php 테스트 시간은 "입니다. ($c_test_time_stop - $c_test_time_start)" n";
    14. 함수 php_test($test_time, $test_data){
    15. for($i=0; $i<$test_time; $i ){
    16. $sum = 0;
    17. foreach($ test_data as $data){
    18. $sum = $data * $data;
    19. }
    20. }
    21. }
    22. 함수 c_test($test_time, $test_data){
    23. for ($i=0; $i<$test_time; $i ){
    24. $sum = array_square_sum($test_data);
    25. }
    26. }
    코드 복사
    테스트 결과는 다음과 같습니다.

      liujun@ubuntu:~/php$ ~/php/bin/php test.php
    1. php 테스트 시간은 30
    2. php 테스트 시간은 2
    코드 복사

    확장 프로그램이 PHP를 직접 사용하는 것보다 15배 빠른 것을 확인할 수 있습니다. 비즈니스 로직이 더욱 복잡해짐에 따라 이러한 차별화는 더욱 커질 것입니다.

    그런 다음 C 언어를 사용하여 직접 수행합니다. 다음은 테스트할 코드입니다(테스트 조건은 정확히 동일합니다).

    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. 이중 합계 = 0;
    10. for(int i=0; i data[i] = i;
    11. }
    12. 구조체 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. 두 배 = (end.tv_sec-start.tv_sec) (end.tv_usec-start.tv_usec) * 1.0 /1000000;
    20. printf("총 시간은 %lfn", time );
    21. printf("총 시간은 %입니다. lfn ", sum);
    22. return 0;
    23. }
    코드 복사

    실행해서 효과를 확인해보면 C를 직접 사용한 시간은 0.261746에 불과해 C 확장을 사용한 경우의 13.09%, PHP를 직접 사용한 경우의 0.87%에 불과한 것을 알 수 있다. 물론 IO와 같은 복잡한 작업이 포함된 경우 C/C는 PHP보다 수만 배 빠릅니다(테스트됨).

    1. liujun@ubuntu:~/php$ g test.cpp -O2 -o test
    2. liujun@ubuntu:~/ php$ ./test
    3. 총 시간은 0.261746
    4. 합계 시간은 36207007178615872.000000
    코드 복사

    따라서 인덱싱, 단어 분할 등 매우 높은 성능이 요구되는 실제 서비스에서는 C를 사용하여 기본 서비스 세트를 만들고 PHP를 사용하여 캡슐화할 수 있습니다. 전화.



성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.