【问题标题】:PHP Extension: Working with class objectsPHP 扩展:使用类对象
【发布时间】:2016-06-10 04:05:23
【问题描述】:

假设我正在创建一个 PHP 7 扩展(在 C,而不是 C++ 中,并且我根本不想要谈论 PHP-CPP 的答案)并且我想创建一个像 Dog 这样的 php 对象并给它变量和扩展本身的功能。

假设我们有一个这样的 PHP 类...

class Dog {
    public name;
    public age;
    private color;

    private function play_ball() {
        echo $this->name . " is playing with a ball!";
    }

    public function get_color() {
        $this->play_ball();
        return $this->color;
    }
}

有人会如何在用 C 编写的扩展中做到这一点?这甚至可能吗?

【问题讨论】:

    标签: c php-extension


    【解决方案1】:

    我会给你一个类的例子,但是我会把这个链接放到 github 因为我认为它会给你一个起点,你可以从那里获得有关如何创建扩展的其余信息

    https://github.com/twigphp/Twig/blob/1.x/ext/twig/twig.c

    这里是类定义代码,它非常冗长,你可以使用宏和函数调用来减少样板代码的数量,但我只是想解释如何去做,而不是向你展示最终的、最好的做所有事情的方法。

    请注意:我没有编译这段代码,虽然我确信它是 99% 准确的,也许你需要修复一些小问题,如果你有疑问,请问我。

    //  I won't include this file, but just look at the twig.c extension source code
    //  It's mostly boilerplate and you just copy and paste what you need
    #include "php_myanimals.h"
    
    //  This is the "class entry" php will use to define your class
    zend_class_entry *dog_ce;
    
    #define DECLARE_MEMBER(type,name,value,access) \
        type(dog_ce, name, strlen(name), value, access TSRMLS_CC)
    
    #define DECLARE_STRING(name,value,access) \
        DECLARE_MEMBER(zend_declare_property_string,name,value,access)
    
    #define DECLARE_LONG(name,value,access) \
        DECLARE_MEMBER(zend_declare_property_long,name,value,access)
    
    #define SET_PARAM(name,value) \
        zend_update_property(dog_ce, this_ptr, name, strlen(name), value TSRMLS_CC)
    
    #define GET_PARAM(name) \
        zend_read_property(dog_ce, this_ptr, name, strlen(name), 1 TSRMLS_CC)
    
    /* {{{ Method: Dog::__construct() */
    PHP_METHOD(dog, __construct)
    {
        zval *name = NULL;
        zval *colour = NULL;
    
        //  First look in the parameter list for a server string 
        //  The | means that all parameters afterwards, are optional
        if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &name, &colour) == FAILURE)
        {
            EX_INVALID_ARG("MyAnimals\\Dog::__construct(string name, [string colour]), parameters were not valid");
        }
    
        SET_PARAM("name",name);
        SET_PARAM("colour",colour);
    }
    /* }}} */
    
    /* {{{ Method: Dog::playBall) */
    PHP_METHOD(dog, playBall)
    {
        php_printf("%s is playing with a ball!", Z_STRVAL_P(GET_PARAM("name")));
    }
    /* }}} */
    
    /* {{{ Method: bool Dog::getColour() */
    PHP_METHOD(dog, getColour)
    {
        //  yeah, the stupid zend engine programmers made a function
        //  that can take 0, 1 or 2 arguments, but if you want 3 or 4 args?
        //  then you have to use this enormous chunk of boilerplate code
        //  see: https://github.com/twigphp/Twig/blob/1.x/ext/twig/twig.c
        //  search for: TWIG_CALL_USER_FUNC_ARRAY
    
        //  You probably should wrap up this ugly shit in a function call
        //  But I've copied it directly here because it's easier
        zend_call_method(
            &this_ptr, Z_OBJCE_P(this_ptr), NULL, 
            //  CAREFUL! php methods are in lower case!!
            "playball", strlen("playball"),
            // this is zval *retval or NULL if you dont want a return value
            NULL,  
            // means zero parameters
            0, 
            // arg 1
            NULL,
            // arg 2 
            NULL 
            TSRMLS_CC
        );
    
        RETURN(GET_PARAM("colour"));
    }
    /* }}} */
    
    ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 1)
        ZEND_ARG_INFO(0, name)
        ZEND_ARG_INFO(0, colour)
    ZEND_END_ARG_INFO()
    
    const zend_function_entry dog_functions[] = {
        //  public methods
        PHP_ME(dog, __construct, arginfo_construct, ZEND_ACC_PUBLIC)
        PHP_ME(dog, getColour, NULL, ZEND_ACC_PUBLIC)
    
        //  protected methods
        PHP_ME(dog, playBall, arginfo_createmanager, ZEND_ACC_PROTECTED)
    
        PHP_FE_END
    };
    
    /* {{{ PHP_MINIT_FUNCTION */
    PHP_MINIT_FUNCTION(MyAnimals)
    {
        zend_class_entry entry;
    
        //  Creates a class like this \MyAnimals\Dog
        INIT_NS_CLASS_ENTRY(entry, "MyAnimals", "Dog", dog_functions);
    
        dog_ce = zend_register_internal_class(&entry TSRMLS_CC);
    
        //  Declare the state / error properties
        DECLARE_STRING("name", "", ZEND_ACC_PUBLIC);
        DECLARE_LONG("age", 0, ZEND_ACC_PRIVATE);
        DECLARE_STRING("colour", "", ZEND_ACC_PROTECTED);
    
        return SUCCESS;
    }
    /* }}} */
    

    【讨论】:

      猜你喜欢
      • 2016-08-26
      • 1970-01-01
      • 2017-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      相关资源
      最近更新 更多