php扩展实践之implements内置接口

这次用 php 扩展的方式来实现一下 Laravel5.1 Support 中的 Fluent,实现一下 php 内置接口 ArrayAccess 的方法

method参数的定义

#include "Zend/zend_interfaces.h"

zend_class_entry *fluent_ce;

ZEND_BEGIN_ARG_INFO_EX(arginfo_fluent___construct, 0, 0, 1)
    ZEND_ARG_ARRAY_INFO(0, attributes, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_fluent_offsetexists, 0, 0, 1)
    ZEND_ARG_INFO(0, offset)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_fluent_offsetget, 0, 0, 1)
    ZEND_ARG_INFO(0, offset)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_fluent_offsetset, 0, 0, 2)
    ZEND_ARG_INFO(0, offset)
    ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_fluent_offsetunset, 0, 0, 1)
    ZEND_ARG_INFO(0, offset)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_fluent___get, 0, 0, 1)
    ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_fluent___set, 0, 0, 2)
    ZEND_ARG_INFO(0, name)
    ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_fluent___isset, 0, 0, 1)
    ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_fluent___unset, 0, 0, 1)
    ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()

定义类方法

ZEND_METHOD(fluent, __construct) {
    zval *attributes, *instance;
    MAKE_STD_ZVAL(attributes);
    array_init(attributes);
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &attributes) == FAILURE) {
        RETURN_NULL();
    }
    instance = getThis();
    zend_update_property(fluent_ce, instance, ZEND_STRL("attributes"), attributes TSRMLS_DC);
}
ZEND_METHOD(fluent, offsetExists) {
    zval *value, *instance, *member;
    char *offset;
    int offsetLen;
    int exists;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset, &offsetLen) == FAILURE) {
        RETURN_NULL();
    }
    instance = getThis();
    MAKE_STD_ZVAL(member);
    ZVAL_STRINGL(member, offset, offsetLen, 1);
    exists = std_object_handlers.has_property(instance, member, 0, 0 TSRMLS_DC);
    zval_ptr_dtor(&member);
    RETURN_BOOL(exists);
}
ZEND_METHOD(fluent, offsetGet) {
    zval *value, *instance;
    char *offset;
    int offsetLen;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset, &offsetLen) == FAILURE) {
        RETURN_NULL();
    }
    instance = getThis();
    php_printf("%s\n", offset);
    value = zend_read_property(fluent_ce, instance, offset, offsetLen, 1 TSRMLS_CC);
    RETURN_ZVAL(value, 1, 0);
}
ZEND_METHOD(fluent, offsetSet) {
    zval *value, *instance;
    char *offset;
    int offsetLen;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &offset, &offsetLen, &value) == FAILURE) {
        RETURN_NULL();
    }
    instance = getThis();
    zend_update_property(fluent_ce, instance, offset, offsetLen, value TSRMLS_DC);
}
ZEND_METHOD(fluent, offsetUnset) {
    zval *instance, *member;
    char *offset;
    int offsetLen;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset, &offsetLen) == FAILURE) {
        RETURN_NULL();
    }
    instance = getThis();
    MAKE_STD_ZVAL(member);
    ZVAL_STRINGL(member, offset, offsetLen, 1);
    std_object_handlers.unset_property(instance, member, 0 TSRMLS_DC);
    zval_ptr_dtor(&member);
}
ZEND_METHOD(fluent, __get) {
    char *name;
    int nameLen;
    zval *attributes, *instance;
    zval **value;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &nameLen) == FAILURE) {
        RETURN_NULL();
    }
    instance = getThis();
    attributes = zend_read_property(fluent_ce, instance, ZEND_STRL("attributes"), 0 TSRMLS_CC);
    if (zend_hash_find(Z_ARRVAL_P(attributes), name, nameLen + 1, (void **)&value) == SUCCESS) {
        RETURN_ZVAL(*value, 1, 0);
    } else {
        RETURN_NULL();
    }
}
ZEND_METHOD(fluent, __set) {
    char *name;
    int nameLen;
    zval *value, *attributes, *instance;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name, &nameLen, &value) == FAILURE) {
        RETURN_NULL();
    }
    instance = getThis();
    attributes = zend_read_property(fluent_ce, instance, ZEND_STRL("attributes"), 0 TSRMLS_CC);
    add_assoc_zval(attributes, name, value);
    zval_add_ref(&value);
}
ZEND_METHOD(fluent, __isset) {
    char *name;
    int nameLen;
    zval *attributes, *instance;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &nameLen) == FAILURE) {
        RETURN_NULL();
    }
    instance = getThis();
    attributes = zend_read_property(fluent_ce, instance, ZEND_STRL("attributes"), 0 TSRMLS_CC);
    if (zend_hash_exists(Z_ARRVAL_P(attributes), name, nameLen + 1) == SUCCESS) {
        RETURN_BOOL(1);
    } else {
        RETURN_BOOL(0);
    }
}
ZEND_METHOD(fluent, __unset) {
    char *name;
    int nameLen;
    zval *attributes, *instance;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &nameLen) == FAILURE) {
        RETURN_NULL();
    }
    instance = getThis();
    attributes = zend_read_property(fluent_ce, instance, ZEND_STRL("attributes"), 0 TSRMLS_CC);
    zend_hash_del(Z_ARRVAL_P(attributes), name, nameLen + 1);
}

static zend_function_entry fluent_methods[] = {
    ZEND_ME(fluent, __construct, arginfo_fluent___construct, ZEND_ACC_CTOR | ZEND_ACC_PUBLIC)
    ZEND_ME(fluent, offsetExists, arginfo_fluent_offsetexists, ZEND_ACC_PUBLIC)
    ZEND_ME(fluent, offsetGet, arginfo_fluent_offsetget, ZEND_ACC_PUBLIC)
    ZEND_ME(fluent, offsetSet, arginfo_fluent_offsetset, ZEND_ACC_PUBLIC)
    ZEND_ME(fluent, offsetUnset, arginfo_fluent_offsetunset, ZEND_ACC_PUBLIC)
    ZEND_ME(fluent, __get, arginfo_fluent___get, ZEND_ACC_PUBLIC)
    ZEND_ME(fluent, __set, arginfo_fluent___set, ZEND_ACC_PUBLIC)
    ZEND_ME(fluent, __isset, arginfo_fluent___isset, ZEND_ACC_PUBLIC)
    ZEND_ME(fluent, __unset, arginfo_fluent___unset, ZEND_ACC_PUBLIC)
    {NULL, NULL, NULL}
};

模块初始化的时候注册类

PHP_MINIT_FUNCTION(learn)
{
    zval *attributes;
    MAKE_STD_ZVAL(attributes);
    array_init(attributes);
    zend_class_entry ce;
    INIT_CLASS_ENTRY(ce, "Fluent", fluent_methods);
    fluent_ce = zend_register_internal_class(&ce TSRMLS_CC);
    // implements ArrayAccess
    zend_class_implements(fluent_ce TSRMLS_DC, 1, zend_ce_arrayaccess);
    zend_declare_property_null(fluent_ce, ZEND_STRL("attributes"), ZEND_ACC_PROTECTED TSRMLS_CC);

    return SUCCESS;
}

标签: none

添加新评论