程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> [轉]自己寫PHP擴展之創建一個類,php一個類

[轉]自己寫PHP擴展之創建一個類,php一個類

編輯:關於PHP編程

[轉]自己寫PHP擴展之創建一個類,php一個類


原文:http://www.imsiren.com/archives/572

比如我們要創建一個類..PHP代碼如下

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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裡面聲明類

1 2 3 4 PHP_METHOD(Person,__construct); PHP_METHOD(Person,__destruct); PHP_METHOD(Person,setproperty); PHP_METHOD(Person,getproperty);

PHP_METHOD宏.
PHP_METHOD 等於ZEND_METHOD
這個宏接受兩個參數,第一個是類名,第二個是類的方法

1 2 3 4 #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.設置接收的參數
我們的方法如果需要接受參數.那麼就要執行

1 2 3 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 11 typedef 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)的定義如下

1 #define ZEND_ARG_INFO(pass_by_ref, name)  { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 },

這三個宏 執行代碼 等於

1 2 3 static 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 7 const 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 7 typedef 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加入如下代碼

1 2 3 4 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 它執行了如下代碼

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 {                                                                                                                       \         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宏定義了長度,所以這裡不用再傳遞長度.
第四個參數是屬性的訪問權限.
還有其他幾個函數用來創建不同類型的屬性

1 2 3 4 5 6 7 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 12 PHP_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

這樣 ..我們用擴展創建的一個基本類就完成了.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved