原文:http://www.imsiren.com/archives/572

比如我们要创建一个类..PHP代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person {
    public $name;
    public $age;
    public function __construct() {
        echo "construct is running!
";
    }
    public function __destruct() {
        echo "
destruct is running!";
    }
    public function getproperty($key) {
        echo $this->$key;
    }
    public function setproperty($key,$val) {
        $this->$key = $val;
    }
}

用PHP来做,很简单..
那么用PHP扩展来写该怎么做?
OK.
1.在php_siren.h里面声明类

1
2
3
4
PHP_METHOD(Person,__construct);
PHP_METHOD(Person,__destruct);
PHP_METHOD(Person,setproperty);
PHP_METHOD(Person,getproperty);

PHP_METHOD宏.
PHP_METHOD 等于ZEND_METHOD
这个宏接受两个参数,第一个是类名,第二个是类的方法

1
2
3
4
#define ZEND_METHOD(classname, name)    ZEND_NAMED_FUNCTION(ZEND_MN(classname##_##name))
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_v    alue_used TSRMLS_DC
//最后等于
void name(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_v    alue_used TSRMLS_DC )

这个宏是用来声明我们的方法…
2.设置接收的参数
我们的方法如果需要接受参数.那么就要执行

1
2
3
ZEND_BEGIN_ARG_INFO_EX(arg_person_info,0,0,2)
        ZEND_ARG_INFO(0,name)
ZEND_END_ARG_INFO()

详细讲这几个宏之前先看看zend_arg_info

1
2
3
4
5
6
7
8
9
10
11
typedef struct _zend_arg_info {
        const char *name; //参数名称
        zend_uint name_len;//长度
        const char *class_name;  //所属类名
        zend_uint class_name_len;  //类名长度
        zend_bool array_type_hint;
        zend_bool allow_null; //允许为空
        zend_bool pass_by_reference;  //引用传值
        zend_bool return_reference;   //引用返回
        int required_num_args;   //参数个数
} zend_arg_info;

ZEND_BEGIN_ARG_INFO_EX定义在Zend/zend_API.h

1
2
3
#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args)       \
        static const zend_arg_info name[] = {                                                                                                                                           \
                { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },

很明显 声明一个zend_arg_info的数组name,然后初始化结构体的值
ZEND_ARG_INFO(0,name)的定义如下

1
#define ZEND_ARG_INFO(pass_by_ref, name)  { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 },

这三个宏 执行代码 等于

1
2
3
static const zend_arg_info name[] = {                                                                                                                                                    { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
{ #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 },
};

3.创建zend_function_entry结构数组

1
2
3
4
5
6
7
const zend_function_entry person_functions[]={
        PHP_ME(Person,__construct,NULL,ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
        PHP_ME(Person,__destruct,NULL,ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
        PHP_ME(Person,getproperty,arg_person_info,ZEND_ACC_PUBLIC)
        PHP_ME(Person,setproperty,arg_person_info,ZEND_ACC_PUBLIC)
        PHP_FE_END
};

zend_function_entry定义如下

1
2
3
4
5
6
7
typedef struct _zend_function_entry {
        const char *fname; //函数名称
        void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
        const struct _zend_arg_info *arg_info;//参数
        zend_uint num_args;//参数个数
        zend_uint flags;//标示PUBLIC ?PRIVATE ?PROTECTED
} zend_function_entry;

PHP_ME宏接收四个参数
1 类名,
2 方法名,
3 zend_arg_info 的参数列表,

ZEND_ACC_PUBLIC ZEND_ACC_PRIVATE ZEND_ACC_PROTECTED是我们类里面的三个访问权限
ZEND_ACC_CTOR标示构造函数
ZEND_ACC_DTOR标示析构函数
4.修改PHP_MINIT_FUNCTION
前面我们说过 PHP_MINIT_FUNCTION是在模块启动的时候执行的函数
首先创建一个全局指针 zend_class_entry *person_ce;
在PHP_MINIT_FUNCTION加入如下代码

1
2
3
4
zend_class_entry person;
INIT_CLASS_ENTRY(person,"Person",person_functions);
person_ce=zend_register_internal_class_ex(&person,NULL,NULL TSRMLS_CC);
zend_declare_property_null(person_ce,ZEND_STRL("name"),ZEND_ACC_PUBLIC TSRMLS_CC);

1行创建一个zend_class_entry对象person.
zend_class_entry这个结构体前面也讲过 PHP内核研究之类的实现
2行初始化zend_class_entry 它执行了如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{                                                                                                                       \
        int _len = class_name_len;                                                              \
        class_container.name = zend_strndup(class_name, _len);  \
        class_container.name_length = _len;                                             \
        class_container.builtin_functions = functions;                  \
        class_container.constructor = NULL;                                             \
        class_container.destructor = NULL;                                              \
        class_container.clone = NULL;                                                   \
        class_container.serialize = NULL;                                               \
        class_container.unserialize = NULL;                                             \
        class_container.create_object = NULL;                                   \
        class_container.interface_gets_implemented = NULL;              \
        class_container.get_static_method = NULL;                               \
        class_container.__call = handle_fcall;                                  \
        class_container.__callstatic = NULL;                                    \
        class_container.__tostring = NULL;                                              \
        class_container.__get = handle_propget;                                 \
        class_container.__set = handle_propset;                                 \
        class_container.__unset = handle_propunset;                             \
        class_container.__isset = handle_propisset;                             \
        class_container.serialize_func = NULL;                                  \
        class_container.unserialize_func = NULL;                                \
        class_container.serialize = NULL;                                               \
        class_container.unserialize = NULL;                                             \
        class_container.parent = NULL;                                                  \
        class_container.num_interfaces = 0;                                             \
        class_container.interfaces = NULL;                                              \
        class_container.get_iterator = NULL;                                    \
        class_container.iterator_funcs.funcs = NULL;                    \
        class_container.module = NULL;                                                  \
}

可以对应文章>> PHP内核研究之类的实现来分析
zend_declare_property_null(person_ce,ZEND_STRL(“name”),ZEND_ACC_PUBLIC TSRMLS_CC);
创建一个值为NULL的属性
第一个参数是类名,第二个参数是 属性名称,第三个参数是属性名的长度,因为ZEND_STRL宏定义了长度,所以这里不用再传递长度.
第四个参数是属性的访问权限.
还有其他几个函数用来创建不同类型的属性

1
2
3
4
5
6
7
zend_declare_property_bool
zend_declare_property_double
zend_declare_property_ex
zend_declare_property_long
zend_declare_property_null
zend_declare_property_string
zend_declare_property_stringl

5.创建 php_siren.h头文件中的方法体

1
2
3
4
5
6
7
8
9
10
11
12
PHP_METHOD(Person,__construct){
        php_printf("construct is running<br>");
}
PHP_METHOD(Person,__destruct){
        php_printf("destruct is running<br>");
}
PHP_METHOD(Person,setproperty){
 
}
PHP_METHOD(Person,getproperty){
 
}

6.最后make&& make install
编译我们的扩展,
重新启动apache.

$p=new Person();
?>
我们就能在浏览器里看到输出的内容

construct is running
destruct is running

这样 ..我们用扩展创建的一个基本类就完成了.

[转]自己写PHP扩展之创建一个类的更多相关文章

  1. linq to sql用partial扩展属性,创建一个部分类(用于多表连接)

    1.在窗体中创建dataGridView显示表: using System; using System.Collections.Generic; using System.ComponentModel ...

  2. C++ //构造函数调用规则 //1.创建一个类,C++编译器会给每个类添加至少3个函数 //默认构造(空实现) //析构函数(空实现) //拷贝函数(值拷贝) //2.如果我们写了有参构造函数 编译器就不会提供默认构造函数 但是会提供拷贝构造函数 //3.如果我们写了拷贝函数 编译器就不再提供 默认 有参 构造函数

    //构造函数调用规则 #include <iostream> using namespace std; //1.创建一个类,C++编译器会给每个类添加至少3个函数 //默认构造(空实现) ...

  3. JS怎么创建一个类?

    15. JS怎么创建一个类? 方式1 : var obj = new Object(); 方式2 : var obj = {}; 16.JS的typeof返回哪些数据类型? string.number ...

  4. 创建一个类Person

    创建一个类Person,包含以下属性:姓名(name).年龄(age).朋友(friends数组).问候(sayhi方法,输出问候语,例如:"你好!").交朋友(addFriend ...

  5. idea快速创建一个类 实现一个接口

    一 创建一个接口类 二  点击接口名称 按alt + ent 三 选择implement interface 选项 完美!!!!!!!

  6. PHP - 创建一个类

    /* * 类的实现 */ //声明一个类 class Person { //私有字段 private $name; private $sex; private $age; //构造函数 functio ...

  7. 用NodeJS创建一个聊天服务器

    Node 是专注于创建网络应用的,网络应用就需要许多I/O(输入/输出)操作.让我们用Node实现有多么简单,并且还能轻松扩展. 创建一个TCP服务器 var net = require('net') ...

  8. 使用PHP来简单的创建一个RPC服务

    RPC全称为Remote Procedure Call,翻译过来为"远程过程调用".主要应用于不同的系统之间的远程通信和相互调用. 比如有两个系统,一个是PHP写的,一个是JAVA ...

  9. 使用PHP创建一个REST API(译)

    最近API在网络领域有些风靡,明确的说是REST的影响力.这实在没什么好惊讶的,因为在任何编程语言中,消费REST API都是非常的容易.构建它也非常的简单,因为本质上你不会用到任何那些已存在很久的H ...

随机推荐

  1. T-SQL Recipes之Dynamic PIVOT and UNPIVOT

    PIVOT PIVOT在行转列的时候经常用到,最便捷的方式就是通过示例来理解它的作用. 示例1 Query to Return Select Product Data from AdventureWo ...

  2. 【BZOJ】4245: [ONTAK2015]OR-XOR

    题意 给定一个长度为\(n(1 \le n \le 500000)\)的序列\(a_i(0 \le a_i \le 10^{18})\),将它划分为\(m(1 \le m \le n)\)段连续的区间 ...

  3. ASP.NET中获取Repeater模板列中LinkButton按钮事件中获取ID等

    前台页面中: <asp:Repeater ID="repComment" runat="server">            <ItemTe ...

  4. BZOJ4488: [Jsoi2015]最大公约数

    Description 给定一个长度为 N 的正整数序列Ai对于其任意一个连续的子序列{Al,Al+1...Ar},我们定义其权值W(L,R )为其长度与序列中所有元素的最大公约数的乘积,即W(L,R ...

  5. spark 大数据 LR测试

    #!/bin/bash size="120Y*10W"date1=`date +%F_%H-%M-%S`config="spark-submit \ --jars /da ...

  6. CYQ.Data 支持WPF相关的数据控件绑定(2013-08-09)

    事件的结果 经过多天的思考及忙碌的开发及测试,CYQ.Data 终于在UI上全面支持WPF,至此,CYQ.Data 已经可以方便支持wpf的开发,同时,框架仍保留最低.net framework2.0 ...

  7. 避免Castle Windsor引起的内存泄露

    原文地址: http://nexussharp.wordpress.com/2012/04/21/castle-windsor-avoid-memory-leaks-by-learning-the-u ...

  8. 借助 Lucene.Net 构建站内搜索引擎(下)

    前言:上一篇我们学习了Lucene.Net的基本概念.分词以及实现了一个最简单的搜索引擎,这一篇我们开始开发一个初具规模的站内搜索项目,通过开发站内搜索模块,我们可以方便地在项目中集成站内搜索功能.本 ...

  9. .Net开发笔记(二十一) 反射在.net中的应用

    反射概念在网上到处都有,但是讲到的具体的应用很少,一个重要的原因是现实中真的很少用得到它.引用msdn上对“反射”的解释: "通过 System.Reflection 命名空间中的类以及 S ...

  10. 深入浅出NodeJS——数据通信,NET模块运行机制

    互联网的运作,最根本的驱动就是信息的交互,NodeJS 在数据交互这一块做的很带感,异步编程让人很惬意,关于 NodeJS 的数据通信,最基础的两个模块是 NET 和 HTTP,前者是基于 TCP 的 ...