博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用扩展开发一个PHP类
阅读量:5988 次
发布时间:2019-06-20

本文共 2991 字,大约阅读时间需要 9 分钟。

原文:http://my.oschina.net/mickelfeng/blog/122519?p=1

假设我们要用PHP扩展实 现一个类Person,它有一个private的成员变量$_name和两个public的实例方法getName()和setName(),可以用 PHP代码表示如下:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
class
Person
{
   
private
$_name
;
   
public
function
getName()
   
{
       
return
$this
-> _name;
   
   
public
function
setName(
$name
)
   
{
       
$this
-> _name =
$name
;
   

1. 声明方法:还使用第一篇文章里面用过的示例,首先在头文件php_fetion_echo.h里加入方法声明。

PHP_METHOD(Person, __construct);PHP_METHOD(Person, __destruct);PHP_METHOD(Person, getName);PHP_METHOD(Person, setName);

前面的扩展在声明函数时使用PHP_FUNCTION宏,而在实现类扩展时我们使用PHP_METHOD宏,第一个参数指定类名,第二个参数指定方法名。

2. 方法实现:在fetion_echo.c文件中实现这几个方法,构造函数和析构函数中只是输出一些文本。

 

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
PHP_METHOD(Person, __construct) {
 
php_printf(
"__construct called."
);
}
 
PHP_METHOD(Person, __destruct) {
 
php_printf(
"__destruct called.<br/>"
);
}
 
PHP_METHOD(Person, getName) {
 
zval *self, *name;
 
self = getThis();
 
name = zend_read_property(Z_OBJCE_P(self), self, ZEND_STRL(
"_name"
), 0 TSRMLS_CC);
 
RETURN_STRING(Z_STRVAL_P(name), 0);
}
 
PHP_METHOD(Person, setName) {
 
char
*arg = NULL;
 
int
arg_len;
 
zval *value, *self;
 
if
(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"s"
, &arg, &arg_len) == FAILURE) {
 
WRONG_PARAM_COUNT;
 
}
 
self = getThis();
 
MAKE_STD_ZVAL(value);
 
ZVAL_STRINGL(value, arg, arg_len, 0);
 
SEPARATE_ZVAL_TO_MAKE_IS_REF(&value);
 
zend_update_property(Z_OBJCE_P(self), self, ZEND_STRL(
"_name"
), value TSRMLS_CC);
 
RETURN_TRUE;
}

对上面的代码做一些解释:

A. 获取方法的参数信息,仍然使用zend_parse_parameters函数,与之前我们介绍过的一样;

B. 获取this指针(相对于PHP代码而言,在PHP扩展中仍然使用zval结构表示)使用getThis()函数;

C. 使用MAKE_STD_ZVAL宏申请并初始化一个zval结构,在PHP扩展中,所有的数据类型其实都是用zval结构来表示的,在本系列文章中我会单独写一篇来介绍zval。

D. 获取属性值使用zend_read_property()函数,使用zend_update_property()函数更新属性值。

3. 初始化类:在扩展初始化函数中,注册并初始化类。

zend_class_entry *person_ce;PHP_MINIT_FUNCTION(fetion_echo){     zend_class_entry person; INIT_CLASS_ENTRY(person, "Person", fetion_echo_functions);    person_ce = zend_register_internal_class_ex(&person, NULL, NULL TSRMLS_CC);    zend_declare_property_null(person_ce, ZEND_STRL("_name"), ZEND_ACC_PRIVATE TSRMLS_CC); return SUCCESS;}

使用INIT_CLASS_ENTRY宏初始化类,第二个参数指定类名,第三个参数是函数表。

4. 注册到函数:声明方法的参数,并注册到函数表中。

ZEND_BEGIN_ARG_INFO(arg_person_setname, 0)    ZEND_ARG_INFO(0, name)ZEND_END_ARG_INFO() const zend_function_entry fetion_echo_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, getName,     NULL, ZEND_ACC_PUBLIC)    PHP_ME(Person, setName,     arg_person_setname, ZEND_ACC_PUBLIC)    {NULL, NULL, NULL} /* Must be the last line in fetion_echo_functions[] */ };

类方法参数的声明与之前我们函数参数声明方式一致,在注册类方法到函数表中时使用PHP_ME宏,而不是之前使用的PHP_FE宏。

ZEND_ACC_PUBLIC:指定方法的访问修饰符

ZEND_ACC_CTOR:指定该方法为构造函数

ZEND_ACC_DTOR:指定该方法为析构函数

5. 运行测试:编译安装扩展后,编写一段简单的测试脚本:

setName("mickelfeng"); echo $person->getName().'
';

运行后可以看到如下输出,说明扩展工作正常:

__construct called.mickelfeng__destruct called.

转载于:https://www.cnblogs.com/orlion/p/5459053.html

你可能感兴趣的文章
Java小细节
查看>>
Citrix VDI实战攻略之八:测试验收
查看>>
注册asp.net 4.0 到iis
查看>>
C++ STL之count函数
查看>>
CentOS7 yum 安装 PHP 5.6.24
查看>>
halcon算子翻译——par_join
查看>>
即时编译器 (JIT) 详解
查看>>
Unity 指定区域随机实例化预制体Prefab 代码
查看>>
判断数据类型
查看>>
webpack配置(一)
查看>>
《机器学习实战》 in python3.x
查看>>
使用命令关闭占用80端口的程序
查看>>
比特币是什么,为什么那么多人对此趋之若鹜?
查看>>
sdkman这个工具好用吗?
查看>>
IIS短文件名漏洞
查看>>
大数据: 完全分布式Hadoop集群-HBase安装
查看>>
CSS Grid布局:网格单元格布局
查看>>
工作问题总结——Could not find stored procedure 'sp_dboption' (找不到存储过程sp_dboption)...
查看>>
FPGA位宽的转换和定义
查看>>
代码中引用res里的颜色、图片
查看>>