PHP 扩展:使用 class 个对象

PHP Extension: Working with class objects

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

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

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 编写的扩展程序中执行此操作?这可能吗?

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

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

这里是 class 定义代码,它非常冗长,您可以使用宏和函数调用来减少样板代码的数量,但我只是想解释如何去做,而不是向您展示做每件事的终极、最佳方式。

请注意:我没有编译这段代码,虽然我确信它是 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;
}
/* }}} */