天天看點

自己寫PHP擴充之操作類的屬性和方法

聲明:本文為斯人原創,全部為作者一一分析得之,有不對的地方望賜教。

歡迎轉載,轉載請注明出處 。

本文位址:http://imsiren.com/archives/581

類建立好了..

那麼類肯定不止這些東西,它由繼承,屬性,傳回值等.

1.方法的參數.

有方法,該方法就可能要有參數.參數是如何傳遞過來的呢?

如果看過之前的文章.那麼你肯定就知道了..是的 與普通函數的參數相同.

聲明char類型的指針用來儲存參數的值.

聲明int類型的變量來儲存的參數長度

然後用到 zend_parse_parameters函數

zend_parse_parameters(``,`< char *type_spec>`,`< ...>`)

該參數有幾個重要的參數

第一個是參數的個數

第二個比較重要,它指定接收參數的類型

下面這份清單完整地列舉出了我們可以指定接收的參數類型:

l – 長整數

d – 雙精度浮點數

s – 字元串 (也可能是空位元組)和其長度

b – 布爾值

r – 資源, 儲存在 zval*

a – 數組, 儲存在 zval*

o – (任何類的)對象, 儲存在 zval*

O – (由class entry 指定的類的)對象, 儲存在 zval*

z – 實際的 zval*

下面的一些字元在類型說明字元串(就是那個 char *type_spec)中具有特别的含義:

| – 表明剩下的參數都是可選參數。如果使用者沒有傳進來這些參數值,那麼這些值就會被初始化成預設值。

/ – 表明參數解析函數将會對剩下的參數以 SEPARATE_ZVAL_IF_NOT_REF() 的方式來提供這個參數的一份拷貝,除非這些參數是一個引用。

! – 表明剩下的參數允許被設定為 NULL(僅用在 a、o、O、r和z身上)。如果使用者傳進來了一個 NULL 值,則存儲該參數的變量将會設定為 NULL。

函數 get接收兩個參數 ,第一個參數是必填字元串類型,第二個參數是可選為整型.

PHP代碼如下

function get($name,$age=0){
 
}
           

如果要在擴充裡實作這樣的功能,zend_parse_parameters的使用如下

char* name;

int name_length;

int age;

int age_length;

zend_parse_parameters(ZEND_NUM_ARGS ,”s|l”,&name,&name_length,&age,&age_len)

zend_parse_parameters 執行失敗的話會傳回FAILURE.

執行成功後,name就是第一個參數的值,age就是第二個參數的值

我們甚至可以調用php_printf函數來輸出.

2.類的屬性

這類的内容在上一篇文章中其實已經講清楚了.

用zend_declare_property_*一系列函數來建立我們的屬性.當然是在PHP_MINIT_FUNCTION函數中建立

以 zend_declare_property_null為例:

zend_declare_property_null(``,`< char *name>`,`< int name_length>`,`< int access_type TSRMLS_DC>`)

ce :是一個zend_class_entry的指針.

name :是屬性的名稱

length :屬性名稱的長度

access_type:屬性的通路級别.

還有其他幾個函數 用法一樣.

zend_declare_property_bool
zend_declare_property_double
zend_declare_property_ex
zend_declare_property_long
zend_declare_property_null
zend_declare_property_string
zend_declare_property_stringl
           

3.讀取屬性

建立了屬性,那麼該如何讀取此屬性呢?

zend_read_property(``,`< zval *object>`,`< char *name>`,`< int name_length>`,`< zend_bool silent TSRMLS_DC>`);

就要使用這個函數了,它将擷取到的屬性資訊傳回到一個zval結構體中

這時候要用到函數getThis();

這個函數會傳回一個zval的指針.

因為是一個對象 是以儲存在結構體_zend_object_value 中

typedef struct _zend_object_value {

zend_object_handle handle;

zend_object_handlers *handlers;

} zend_object_value;

第一個參數會調用 zend_object_handler所指向的函數指針get_class_entry來擷取目前執行的類的資訊.

第一個參數應該是 Z_OBJEC_P(getThis());

第二個參數是 getThis();

第三個參數是要擷取的屬性

第四個參數是屬性的長度.

修改之後的getproperty方法

PHP_METHOD(Person,getproperty){
        zval* self=getThis();
        zval* name;
        name=zend_read_property(Z_OBJCE_P(self),self,ZEND_STRL("name"),0 TSRMLS_CC);
        php_printf("%s",name->value.str.val);
}
           

4.設定屬性

該如何更新屬性的值呢?

同樣給我們提供了一個函數

zend_update_property(``,`< zval *object>`,`< char *name>`,`< int name_length>`,`< zval *value TSRMLS_DC>`)

前四個參數與zend_read_property相同.

不同的是最後一個zval*value.它是我們屬性的值..因為他是一個zval的指針,是以我們需要将通過zend_parse_parameters擷取到的參數轉為一個zval的指針.

修改後的setproperty方法.

PHP_METHOD(Person,setproperty){
        char *key=NULL;
        int key_len;
        char *val=NULL;
        int val_len;
        zval* self=getThis();
        zval* value;
        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"ss",&key,&key_len,&val,&val_len)==FAILURE){
                return;
        }
        MAKE_STD_ZVAL(value);
        ZVAL_STRINGL(value,val,val_len,1);
        zend_update_property(Z_OBJCE_P(self),self,key,key_len,value TSRMLS_CC);
           

最後make && make install,重新開機apache.

這樣我們在 php代碼裡.

<?php
$a=new Person();
$a->setproperty("name","this is siren");
$a->getproperty();
?>
           

就可以輸出我們通過setproperty設定的值了.

原文出處: http://imsiren.com/archives/581