原文:http://www.imsiren.com/archives/572
比如我們要創建一個類..PHP代碼如下
class
Person {
public
$name
;
public
$age
;
public
function
__construct() {
echo
"construct is running!
";
}
public
function
__destruct() {
echo
"
destruct is running!";
}
public
function
getproperty(
$key
) {
echo
$this
->
$key
;
}
public
function
setproperty(
$key
,
$val
) {
$this
->
$key
=
$val
;
}
}
用PHP來做,很簡單..
那麼用PHP擴展來寫該怎麼做?
OK.
1.在php_siren.h裡面聲明類
PHP_METHOD(Person,__construct);
PHP_METHOD(Person,__destruct);
PHP_METHOD(Person,setproperty);
PHP_METHOD(Person,getproperty);
PHP_METHOD宏.
PHP_METHOD 等於ZEND_METHOD
這個宏接受兩個參數,第一個是類名,第二個是類的方法
#define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_MN(classname##_##name))
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_v alue_used TSRMLS_DC
//最後等於
void
name(
int
ht, zval *return_value, zval **return_value_ptr, zval *this_ptr,
int
return_v alue_used TSRMLS_DC )
這個宏是用來聲明我們的方法…
2.設置接收的參數
我們的方法如果需要接受參數.那麼就要執行
ZEND_BEGIN_ARG_INFO_EX(arg_person_info,0,0,2)
ZEND_ARG_INFO(0,name)
ZEND_END_ARG_INFO()
詳細講這幾個宏之前先看看zend_arg_info
1 2 3 4 5 6 7 8 9 10 11typedef
struct
_zend_arg_info {
const
char
*name;
//參數名稱
zend_uint name_len;
//長度
const
char
*class_name;
//所屬類名
zend_uint class_name_len;
//類名長度
zend_bool array_type_hint;
zend_bool allow_null;
//允許為空
zend_bool pass_by_reference;
//引用傳值
zend_bool return_reference;
//引用返回
int
required_num_args;
//參數個數
} zend_arg_info;
ZEND_BEGIN_ARG_INFO_EX定義在Zend/zend_API.h
1 2 3#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
static
const
zend_arg_info name[] = { \
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
很明顯 聲明一個zend_arg_info的數組name,然後初始化結構體的值
ZEND_ARG_INFO(0,name)的定義如下
#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 },
這三個宏 執行代碼 等於
1 2 3static
const
zend_arg_info name[] = { { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
{ #name,
sizeof
(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 },
};
3.創建zend_function_entry結構數組
1 2 3 4 5 6 7const
zend_function_entry person_functions[]={
PHP_ME(Person,__construct,NULL,ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(Person,__destruct,NULL,ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
PHP_ME(Person,getproperty,arg_person_info,ZEND_ACC_PUBLIC)
PHP_ME(Person,setproperty,arg_person_info,ZEND_ACC_PUBLIC)
PHP_FE_END
};
zend_function_entry定義如下
1 2 3 4 5 6 7typedef
struct
_zend_function_entry {
const
char
*fname;
//函數名稱
void
(*handler)(INTERNAL_FUNCTION_PARAMETERS);
const
struct
_zend_arg_info *arg_info;
//參數
zend_uint num_args;
//參數個數
zend_uint flags;
//標示PUBLIC ?PRIVATE ?PROTECTED
} zend_function_entry;
PHP_ME宏接收四個參數
1 類名,
2 方法名,
3 zend_arg_info 的參數列表,
ZEND_ACC_PUBLIC ZEND_ACC_PRIVATE ZEND_ACC_PROTECTED是我們類裡面的三個訪問權限
ZEND_ACC_CTOR標示構造函數
ZEND_ACC_DTOR標示析構函數
4.修改PHP_MINIT_FUNCTION
前面我們說過 PHP_MINIT_FUNCTION是在模塊啟動的時候執行的函數
首先創建一個全局指針 zend_class_entry *person_ce;
在PHP_MINIT_FUNCTION加入如下代碼
zend_class_entry person;
INIT_CLASS_ENTRY(person,
"Person"
,person_functions);
person_ce=zend_register_internal_class_ex(&person,NULL,NULL TSRMLS_CC);
zend_declare_property_null(person_ce,ZEND_STRL(
"name"
),ZEND_ACC_PUBLIC TSRMLS_CC);
1行創建一個zend_class_entry對象person.
zend_class_entry這個結構體前面也講過 PHP內核研究之類的實現
2行初始化zend_class_entry 它執行了如下代碼
{ \
int
_len = class_name_len; \
class_container.name = zend_strndup(class_name, _len); \
class_container.name_length = _len; \
class_container.builtin_functions = functions; \
class_container.constructor = NULL; \
class_container.destructor = NULL; \
class_container.clone = NULL; \
class_container.serialize = NULL; \
class_container.unserialize = NULL; \
class_container.create_object = NULL; \
class_container.interface_gets_implemented = NULL; \
class_container.get_static_method = NULL; \
class_container.__call = handle_fcall; \
class_container.__callstatic = NULL; \
class_container.__tostring = NULL; \
class_container.__get = handle_propget; \
class_container.__set = handle_propset; \
class_container.__unset = handle_propunset; \
class_container.__isset = handle_propisset; \
class_container.serialize_func = NULL; \
class_container.unserialize_func = NULL; \
class_container.serialize = NULL; \
class_container.unserialize = NULL; \
class_container.parent = NULL; \
class_container.num_interfaces = 0; \
class_container.interfaces = NULL; \
class_container.get_iterator = NULL; \
class_container.iterator_funcs.funcs = NULL; \
class_container.module = NULL; \
}
可以對應文章>> PHP內核研究之類的實現來分析
zend_declare_property_null(person_ce,ZEND_STRL(“name”),ZEND_ACC_PUBLIC TSRMLS_CC);
創建一個值為NULL的屬性
第一個參數是類名,第二個參數是 屬性名稱,第三個參數是屬性名的長度,因為ZEND_STRL宏定義了長度,所以這裡不用再傳遞長度.
第四個參數是屬性的訪問權限.
還有其他幾個函數用來創建不同類型的屬性
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
5.創建 php_siren.h頭文件中的方法體
1 2 3 4 5 6 7 8 9 10 11 12PHP_METHOD(Person,__construct){
php_printf(
"construct is running<br>"
);
}
PHP_METHOD(Person,__destruct){
php_printf(
"destruct is running<br>"
);
}
PHP_METHOD(Person,setproperty){
}
PHP_METHOD(Person,getproperty){
}
6.最後make&& make install
編譯我們的擴展,
重新啟動apache.
$p=new Person();
?>
我們就能在浏覽器裡看到輸出的內容
construct is running
destruct is running
這樣 ..我們用擴展創建的一個基本類就完成了.