天天看點

PHP擴充開發(7):zval結構

轉載自:http://terrylee.me/blog/post/2011/02/12/php-extension-part1.aspx

在前面的文章多次提到了zval結構,其實所有使用者定義的變量在PHP中都是用zval類型來表示的,當我門 使用zend_parse_parameters函數解析參數時,Zend引擎會根據相應的資料類型進行類型轉換,而由于PHP中的數組、對象和資源類 型,在C語言中沒有對應的類型,是以無法進行類型轉換,它們都使用zval表示,先看一下zval結構定義:

typedef pval zval;

typedef struct _zval_struct zval;

struct _zval_struct {
    /* Variable information */
    zvalue_value value; /* value */
    unsigned char type; /* active type */
    unsigned char is_ref;
    short refcount;
};

      

zval結構的定義使用了C語言中的聯合類型,各個字段說明如下:

value    變量内容的聯合,參見“表3.6 Zend zvalue_value 結構”

type    變量的類型。“表3.7 Zend 變量類型”給出了一個完整的變量類型清單

is_ref    0 表示這個變量還不是一個引用。1 表示這個變量還有被别的變量所引用

refcount    表示這個變量是否仍然有效。每增加一個對這個變量的引用,這個數值就增加 1。反之,每失去一個對這個變量的引用,該值就會減1。當引用計數減為0的時候,就說明已經不存在對這個變量的引用了,于是這個變量就會自動釋放

變量類型定義:

IS_NULL    表示是一個空值 NULL

IS_LONG    是一個(長)整數

IS_DOUBLE    是一個雙精度的浮點數

IS_STRING    是一個字元串

IS_ARRAY    是一個數組

IS_OBJECT    是一個對象

IS_BOOL    是一個布爾值

IS_RESOURCE    是一個資源(關于資源的讨論,我們以後會在适當的時候讨論到它)

IS_STRING    是一個常量

zvalue_value結構定義:

typedef union _zvalue_value {
    long lval; /* long value */
    double dval; /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht; /* hash table value */
    struct {
        zend_class_entry *ce;
        HashTable *properties;
    } obj;
} 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 就用這個屬性值

給定一個具體的zval,可用三個便利的宏中的一個測試它的類型:Z_TYPE(zval)、Z_TYPE_P(zval*)或Z_TYPE_PP(zval**)。三者之間僅有的功能上的差別在于傳入的變量所期望的間接的級别。如下面的示例:

PHP_FUNCTION(hello_dump)
{
    zval *uservar;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z",
     &uservar) == FAILURE) {
        RETURN_NULL();
    }

    switch (Z_TYPE_P(uservar)) {
        case IS_NULL:
            php_printf("NULL/n");
            break;
        case IS_BOOL:
            php_printf("Boolean: %s/n", Z_LVAL_P(uservar) ? "TRUE" : "FALSE");
            break;
        case IS_LONG:
            php_printf("Long: %ld/n", Z_LVAL_P(uservar));
            break;
        case IS_DOUBLE:
            php_printf("Double: %f/n", Z_DVAL_P(uservar));
            break;
        case IS_STRING:
            php_printf("String: ");
            PHPWRITE(Z_STRVAL_P(uservar), Z_STRLEN_P(uservar));
            php_printf("/n");
            break;
        case IS_RESOURCE:
            php_printf("Resource/n");
            break;
        case IS_ARRAY:
            php_printf("Array/n");
            break;
        case IS_OBJECT:
            php_printf("Object/n");
            break;
        default:
            php_printf("Unknown/n");
    }

    RETURN_TRUE;
}
 

      

編寫一個簡單的測試腳本:

<?php 
    hello_dump(1234);
    echo '<br/>';
    hello_dump('terrylee');
    echo '<br/>';
    hello_dump(array('foo', 'bar'));
?>
 

      

運作後效果如下:

PHP擴充開發(7):zval結構

在PHP擴充中對于使用者傳過來的參數,本質上都是一個zval結構,我們需要調用一些轉換函數進行強制類型轉換(zend_parse_parameters函數會對基本類型做轉換),Zend引擎提供了convert_to_xxx系列函數幫助我們進行類型轉換:

convert_to_boolean_ex()

    強制轉換為布爾類型。若原來是布爾值則保留,不做改動。長整型值0、雙精度型值0.0、空字元串或字元串‘0’還有空值 NULL 都将被轉換為 FALSE(本質上是一個整數 0)。數組和對象若為空則轉換為 FALSE,否則轉為 TRUE。除此之外的所有值均轉換為 TRUE(本質上是一個整數 1)。

convert_to_long_ex()

    強制轉換為長整型,這也是預設的整數類型。如果原來是空值NULL、布爾型、資源當然還有長整型,則其值保持不變(因為本質上都是整數 0)。雙精度型則被簡單取整。包含有一個整數的字元串将會被轉換為對應的整數,否則轉換為 0。空的數組和對象将被轉換為 0,否則将被轉換為 1。

convert_to_double_ex()

    強制轉換為一個雙精度型,這是預設的浮點數類型。如果原來是空值 NULL 、布爾值、資源和雙精度型則其值保持不變(隻變一下變量類型)。包含有一個數字的字元串将被轉換成相應的數字,否則被轉換為 0.0。空的數組和對象将被轉換為 0.0,否則将被轉換為 1.0。

convert_to_string_ex()

    強制轉換為數組。若原來就是一數組則不作改動。對象将被轉換為一個以其屬性為鍵名,以其屬性值為鍵值的數組。(方法強制轉換為字元串。空值 NULL 将被轉換為空字元串。布爾值 TRUE 将被轉換為 ‘1’,FALSE 則被轉為一個空字元串。長整型和雙精度型會被分别轉換為對應的字元串,數組将會被轉換為字元串‘Array’,而對象則被轉換為字元串‘Object’。

convert_to_array_ex(value)

    強制轉換為數組。若原來就是一數組則不作改動。對象将被轉換為一個以其屬性為鍵名,以其屬性值為鍵值的數組。(方法将會被轉化為一個‘scalar’鍵, 鍵值為方法名)空值 NULL 将被轉換為一個空數組。除此之外的所有值都将被轉換為僅有一個元素(下标為 0)的數組,并且該元素即為該值。

convert_to_object_ex(value)

    強制轉換為對象。若原來就是對象則不作改動。空值 NULL 将被轉換為一個空對象。數組将被轉換為一個以其鍵名為屬性,鍵值為其屬性值的對象。其他類型則被轉換為一個具有‘scalar’屬性的對象,‘scalar’屬性的值即為該值本身。

convert_to_null_ex(value)

    強制轉換為空值 NULL。

關于zval結構的介紹就到這裡了。