2015年11月28日 星期六

[PHP] PHP Extension 寫 php class 類別

基礎請參考:
PHP 也有 Day #21 從 C 語言到 PHP Extension 錄影

實作一個在 PHP 是這樣的一個類別
Class MyClass {
    protected $name = "";
    public function __construct($name) {
        $this->name = $name;
    }
    public function getName() {
        return $this->name;
    }
    public function setName($name) {
        $this->name = $name;
    }
    public function helloWorld() {
        return "Hello World";
    }
}
在 extension.c 寫完會如下
#include "php_myclass.h"

#if COMPILE_DL_MYCLASS
    ZEND_GET_MODULE(myclass)
#endif
// 宣告一個 global zend_class_entry 變數
zend_class_entry *myclass_ce;

/*
    這裡由原本的 PHP_FE 改用 PHP_ME
    四個參數為
    className:class PHP 呼叫的名字
    methodName:method 呼叫的名字
    arg_info:先帶 NULL,可以設定帶進來的參數值,可參考 http://www.walu.cc/phpbook/preface.md
    flags:有以下參數 ZEND_ACC_PUBLIC, ZEND_ACC_PROTECTED, ZEND_ACC_PRIVATE, ZEND_ACC_STATIC, ZEND_ACC_FINAL, ZEND_ACC_ABSTRACT
           分別表示   public         , protected         , private         , static         , final         , abstract
    如果要寫 abstract method 是使用 PHP_ABSTRACT_ME,就可以不用實作內容

    下述就是定義 MyClass 這個類別
    有 php 的 construct public funciton __construct
    一般 method 有
    public funciton getName
    public funciton setName
    public funciton helloWord
 */
static const zend_function_entry myclass_functions[] = {
    PHP_ME(MyClass, __construct,        NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
    PHP_ME(MyClass, getName,            NULL, ZEND_ACC_PUBLIC)
    PHP_ME(MyClass, setName,            NULL, ZEND_ACC_PUBLIC)
    PHP_ME(MyClass, helloWorld,         NULL, ZEND_ACC_PUBLIC)
    PHP_FE_END
};

/*
    原本這裡的第三個參數改成 NULL,它原本是帶上面這個 zend_function_entry 的變數
    第四個參數改成 PHP_MINIT(myclass)
    class 改成要在 module init 這個周期宣告 class
    Ref:http://www.walu.cc/phpbook/1.3.md
 */
zend_module_entry myclass_module_entry = {
    STANDARD_MODULE_HEADER,
    "myclass",                       // your extension name
    NULL,                            // where you define your functions
    PHP_MINIT(myclass),              // for module initialization
    NULL, // PHP_MSHUTDOWN(myclass), // for module shutdown process
    NULL, // PHP_RINIT(myclass)      // for request initialization
    NULL, // PHP_RSHUTDOWN(myclass)  // for reqeust shutdown process
    NULL, // PHP_MINFO(myclass),     // for providing module information
    "0.1",
    STANDARD_MODULE_PROPERTIES
};

/*
    PHP_MINIT(myclass) 實作內容
    註冊一個叫 MyClass 的類別
    myclass_functions 也在這裡被使用
    全域的 myclass_ce 內容在這裡實際取得
 */
PHP_MINIT_FUNCTION(myclass)
{
    zend_class_entry tmp_ce;
    INIT_CLASS_ENTRY(tmp_ce, "MyClass", myclass_functions);
    myclass_ce = zend_register_internal_class(&tmp_ce TSRMLS_CC);
    return SUCCESS;
}

/*
    實作 __construct
    大致跟之前寫 function 差不多

    不過這裡有用 zend_update_property* 的 function
    這一系列的都是用來設定 class property
    全域的 myclass_ce 也在這裡被使用到,寫進 myclass_ce 的意思

    這裡我用來設定
    Class MyClass {
        protected $name = "";
    }
    這個 name property

    getThis() 是取得這個 class handle

    Ref:http://www.walu.cc/phpbook/11.2.md
 */
PHP_METHOD(MyClass, __construct)
{
    char *name = NULL;
    int name_len;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|", &name, &name_len) == FAILURE) {
        RETURN_NULL();
    }
    zend_update_property_stringl(myclass_ce, getThis(), "name", sizeof("name") - 1, name, name_len TSRMLS_CC);
}

/*
    實作 getName
    zend_parse_parameters_none 判斷不能傳參數進來
    zend_read_property 取得 name 這個 property
    Z_STRVAL_P 從 zval 取得 string
    RETURN_STRING Return string
*/
PHP_METHOD(MyClass, getName)
{
    zval *name = NULL;
    if (zend_parse_parameters_none() == FAILURE) {
        RETURN_FALSE;
    }
    name = zend_read_property(myclass_ce, getThis(), "name", sizeof("name") - 1, 1 TSRMLS_CC);
    RETURN_STRING(Z_STRVAL_P(name), 1);
}

/*
    實作 setName
*/
PHP_METHOD(MyClass, setName)
{
    char *name = NULL;
    int name_len;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|", &name, &name_len) == FAILURE) {
        RETURN_NULL();
    }
    zend_update_property_stringl(myclass_ce, getThis(), "name", sizeof("name") - 1, name, name_len TSRMLS_CC);
}

/*
    實作 helloWorld
*/
PHP_METHOD(MyClass, helloWorld)
{
    if (zend_parse_parameters_none() == FAILURE) {
        RETURN_FALSE;
    }

    RETURN_STRING("Hello World", 1);
}




沒有留言:

張貼留言