c擴展調用php的函數(調用實現php函數的c函數)

上一次是寫的c擴展調用c的標準函數,可是隻能調用頭文件中申明的函數,今天來講下c擴展調用實現php函數的c函數,比方說,c擴展要用到php中ip2long這個函數,可是c不可能去php中調用,確定是去調用實現php函數的c函數。那麼c擴展如何調用c內核對php的API呢?php

這裏要用到一個函數:ZEND_API int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC);數組

 

第一個參數是HashTable,Zend使用HashTable來存儲PHP函數,function_table用於指定從哪一個HashTable中獲取函數。一般應該用CG(function_table),展開就是compiler_globals.function_table,compiler_globals是一個用來存儲編譯器數據的全局數據結構(與其對應的還有個EG宏,即executor_globals,它用來存儲執行器數據)。compiler_globals.function_table裏面存儲了全部咱們能夠在PHP頁面裏面調用的函數,包括Zend內建函數、PHP標準庫函數、模塊導出的函數以及用戶使用PHP代碼定義的函數。數據結構

 object_pp是一個對象,當指定該值時,Zend會從對象的函數表中獲取函數,這裏不予討論,老是設爲NULL。函數

function_name必須是string型的zval,存儲咱們但願調用的函數的名稱。爲何使用zval而不是直接用char*,是由於Zend考慮到大部分狀況下,咱們都是從用戶那得到參數,而後再調用call_user_function_ex的,這樣就能夠不做處理直接把用戶參數傳給該函數。固然,咱們也能夠手動建立一個string型zval傳給它。學習

retval_ptr_ptr用於獲取函數的返回值,Zend執行完指定的函數後,它就將返回值的指針填充到這裏。這個容器的空間函數會自動幫你申請,因此咱們無需手動申請,但在過後這個容器空間的銷燬釋放工做得由咱們本身(使用 zval_dtor())來作。ui

param_count和params用於指定函數的參數,param_count是一個標識參數個數的整數,params[] 是一個包含具體參數的數組。spa

no_separation用於指定是否在必要時執行zval分離,這在寫入非引用zval時發生。應該老是將其設爲0,表示執行zval分離,不然可能破壞數據。指針

symbol_table用於指定目標函數的active_symbol_table,一般應該使用NULL,這樣Zend會爲目標函數生成一個空的符號表。下面來看一個具體例子:對象

 

我在c擴展中要使用php函數中的ip2long函數,那麼調用方法ip

unsigned long ip2longs(const char* ip){  

  zval *funname,*ret_ptr = NULL,*args,**params[1],*args_2;   //若是有多個參數,比方說兩個參數,就繼續定義變量,看紅色部分,若是繼續加參數,按紅色的步驟繼續,定義變量,賦值,放入數組,參數個數也要變
  MAKE_STD_ZVAL(funname);     //建立變量
  ZVAL_STRING(funname, "ip2long", 1);  //設置好zval的類型和值,第二個參數就是咱們要調用的ip2long函數 ,這兩個方法不瞭解的能夠查看http://www.cunmou.com/phpbook/2.3.md

  MAKE_STD_ZVAL(args);
  ZVAL_STRING(args,ip,1);

  MAKE_STD_ZVAL(args_2);
  ZVAL_LONG(args_2,123); //這是第二個參數,建立變量並賦值,整形只有兩個參數,別的類型能夠上網查

  params[0] = &args;  //把參數放入數組中

  params[1] = &args_2; // 放入數組

  call_user_function_ex(EG(function_table), NULL, funname, &ret_ptr, 2, params, 0, EG(active_symbol_table));  //調用函數,第5個參數表明參數個數咱們這是2

  zval_ptr_dtor(&ret_ptr); //銷燬手動建立的空間

  return ret_ptr->value.lval;  //獲取返回的值,由於函數返回是一個long型的,因此取lval
}

//該函數是php能夠直接調用的函數。功能是用來判斷某個ip是否在內網中

PHP_FUNCTION(is_intranet) {
  char *ip;
  int ip_length=0;
  if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"s",&ip,&ip_length) == FAILURE){
    RETURN_NULL();
  }
  unsigned long ip_long = ip2longs(ip);   //調用聲明的函數
  if(ip_long == ip2longs("127.0.0.1") || (ip_long > ip2longs("10.0.0.0") && ip_long <= ip2longs("10.255.255.255")) ||
  (ip_long >= ip2longs("172.16.0.0") && ip_long <= ip2longs("172.31.255.255")) ||
  (ip_long >= ip2longs("192.168.0.0") && ip_long <= ip2longs("192.168.255.255"))
  ) {
    RETURN_BOOL(1);
  } else {
    RETURN_BOOL(0);
  }
}

這裏在多說下zval的結構,這些是本身平時學習總結的,在此拿出來和你們分享:

php中的存儲的基本單元是zval(Zend Value),zval結構,其實全部用戶定義的變量在PHP中都是用zval類型來表示的,當我門 使用zend_parse_parameters函數解析參數時,Zend引擎會根據相應的數據類型進行類型轉換,而因爲PHP中的數組、對象和資源類 型,在C語言中沒有對應的類型,因此沒法進行類型轉換,它們都使用zval表示。
 
struct _zval_struct {
    zvalue_value value; 
    unsigned char type; 
    unsigned char is_ref;
    short refcount;
};
typedef struct _zval_struct zval;
 
結構體字段解釋:
     (1) zval_value value   

變量的實際值,具體來講是一個zvalue_value的聯合體(union):

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {                    /* string */
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value,used for array */
    zend_object_value obj;      /* object */
} zvalue_value;
     

zvalue_value結構的說明以下:

lval    若是變量類型爲 IS_LONG、IS_BOOLEAN 或 IS_RESOURCE 就用這個屬性值 
dval    若是變量類型爲 IS_DOUBLE 就用這個屬性值 
str    若是變量類型爲 IS_STRING 就訪問這個屬性值。它的字段 len 表示這個字符串的長度,字段 val 則指向該字符串。因爲 Zend 使用的是 C 風格的字符串,所以字符串的長度就必須把字符串末尾的結束符 0×00 也計算在內 
ht    若是變量類型爲數組,那這個 ht 就指向數組的哈希表入口 
obj    若是變量類型爲 IS_OBJECT 就用這個屬性值
 
 
(2)type
     zval *uservar;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z",
     &uservar) == FAILURE) {
        RETURN_NULL();
    }
 
結構體的type的值以下:    獲取類型經過 Z_TYPE_P(uservar);
IS_NULL    表示是一個空值 NULL 
IS_LONG    是一個(長)整數 
IS_DOUBLE    是一個雙精度的浮點數 
IS_STRING    是一個字符串 
IS_ARRAY    是一個數組 
IS_OBJECT    是一個對象 
IS_BOOL    是一個布爾值 
IS_RESOURCE    是一個資源(關於資源的討論,咱們之後會在適當的時候討論到它) 
IS_STRING    是一個常量
 
(3)is_ref
      0 表示這個變量還不是一個引用。1 表示這個變量還有被別的變量所引用
 
(4) refcount    表示這個變量是否仍然有效。每增長一個對這個變量的引用,這個數值就增長 1。反之,每失去一個對這個變量的引用,該值就會減1。當引用計數減爲0的時候,就說明已經不存在對這個變量的引用了,因而這個變量就會自動釋放
相關文章
相關標籤/搜索