PHP扩展:使用类对象

时间:2016-06-10 04:05:24

标签: c php-extension

假设我正在创建一个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编写的扩展中执行此操作?这甚至可能吗?

1 个答案:

答案 0 :(得分:2)

我会给你一个关于这个课程的例子,但我会把这个链接放到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;
}
/* }}} */