C10P-PHP,用C实现PHP扩展类

  • Post author:
  • Post category:php


前面简单介绍了用C语言实现PHP扩展的步骤,见php扩展开发步骤示例,那个是扩展一个函数,这里讲述一下如何用C扩展PHP类。

准备实现的类如下:

class Rectangle{

private $_width;

private $_height;

public function __construct($width, $height){

$this->_width = $width;

$this->_height = $height;

}

public function clone(){

return new Rectangle($this->_width, $this->_height);

}

public function setWidth($width){

$this->_width = $width;

}

public function setHeight($height){

$this->_height = $height;

}

public function getWidth(){

return $this->_width;

}

public function getHeight(){

return $this->_height;

}

public function getArea(){

return $this->_width * $this->_height;

}

public function getCircle(){

return ($this->_width + $this->_height) * 2;

}

}

实现类扩展的步骤如下:(首先下载PHP源码,这里使用的是php-5.2.8)

1. 建立扩展骨架

cd php-5.2.8/ext

./ext_skel –extname=class_ext

2. 修改编译参数

cd php-5.2.8/ext/class_ext

vi config.m4

去掉

PHP_ARG_ENABLE(class_ext, whether to enable class_ext support,

[   –enable-class_ext       Enable class_ext support])

两行前面的dnl,修改后为:

dnl Otherwise use enable:

PHP_ARG_ENABLE(class_ext, whether to enable class_ext support,

dnl Make sure that the comment is aligned:

[  –enable-class_ext           Enable class_ext support])

3. 编写C代码

cd php-5.2.8/ext/class_ext

vi php_class_ext.h

在 PHP_FUNCTION(confirm_class_ext_compiled); 后面增加申明函数:

PHP_METHOD(Rectangle,__construct);

PHP_METHOD(Rectangle,clone);

PHP_METHOD(Rectangle,setWidth);

PHP_METHOD(Rectangle,setHeight);

PHP_METHOD(Rectangle,getWidth);

PHP_METHOD(Rectangle,getHeight);

PHP_METHOD(Rectangle,getArea);

PHP_METHDO(Rectangle,getCircle);

vi class_ext.c

#申明方法的参数,注册到函数表中

ZEND_BEGIN_ARG_INFO(arg_construct,2)

ZEND_ARG_INFO(0, width)

ZEND_ARG_INFO(0, height)

ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arg_set_width,1)

ZEND_ARG_INFO(0, width)

ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arg_set_height,1)

ZEND_ARG_INFO(0, height)

ZEND_END_ARG_INFO()

const zend_function_entry class_ext_functions[] = {

PHP_FE(confirm_class_ext_compiled, NULL)

PHP_ME(Rectangle, __construct, arg_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)

PHP_ME(Rectangle, clone, NULL, ZEND_ACC_PUBLIC)

PHP_ME(Rectangle, setWidth, NULL, ZEND_ACC_PUBLIC)

PHP_ME(Rectangle, setHeight, NULL, ZEND_ACC_PUBLIC)

PHP_ME(Rectangle, getWidth, NULL, ZEND_ACC_PUBLIC)

PHP_ME(Rectangle, getHeight, NULL, ZEND_ACC_PUBLIC)

PHP_ME(Rectangle, getArea, NULL, ZEND_ACC_PUBLIC)

PHP_ME(Rectangle, getCircle, NULL, ZEND_ACC_PUBLIC)

{NULL, NULL, NULL}  /* Must be the last line in class_ext_functions[] */

};

#其中ZEND_ACC_CTOR表示构造函数,ZEND_ACC_PUBLIC表示访问权限为PUBLIC。

#接下来,在模块初始化函数中注册并初始化类

zend_class_entry *Rectangle_ce; //zend内部类结构变量

PHP_MINIT_FUNCTION(class_ext)

{

zend_class_entry Rectangle;

INIT_CLASS_ENTRY(Rectanble, “Rectangle”, class_ext_functions); //第二个参数为类名,第三个参数为类的函数列表

Rectangle_ce = zend_register_internal_class_ex(&Rectangle, NULL, NULL TSRMLS_CC); //注册类

zend_declare_property_null(Rectangle_ce, ZEND_STRL(“_width”), ZEND_ACC_PRIVATE TSRMLS_CC); //初始化类的属性_width

zend_declare_property_null(Rectangle_ce, ZEND_STRL(“_height”), ZEND_ACC_PRIVATE TSRMLS_CC);  //初始化类的属性_height

return SUCCESS;

}

#在文件最后增加类的成员函数的具体实现代码

PHP_METHOD(Rectangle, __construct)

{

long width,height;

if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “ll”, &width, &height) == FAILURE){ //获取构造函数的两个函数参数_width和_height

WRONG_PARAM_COUNT;

}

if( width <= 0 ) {

width = 1; //如果_width为0,则赋默认值1

}

if( height <= 0 ) {

height = 1; //如果_height为0,则赋默认值1

}

zend_update_property_long(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_width”), width TSRMLS_CC); //更新类成员变量_width的值

zend_update_property_long(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_height”), height TSRMLS_CC);  //更新类成员变量_height的值

RETURN_TRUE;

}

PHP_METHOD(Rectangle, clone)

{

zval *clone_obj;

zval *width,*height;

MAKE_STD_ZVAL(clone_obj);

object_init_ex(clone_obj, Rectangle_ce); //初始化对象,对象所属的类为Rectangle_ce

width = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_width”), 0 TSRMLS_CC); //获取类成员变量_width的值

height = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_height”), 0 TSRMLS_CC); //获取类成员变量_height的值

zend_update_property_long(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_width”), width TSRMLS_CC); //更新Rectangle_ce类对象clone_obj的属性值_width

zend_update_property_long(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_height”), height TSRMLS_CC); //更新Rectangle_ce类对象clone_obj的属性值_height

RETURN_ZVAL(clone_obj, 1, 0);  //返回该对象

}

PHP_METHOD(Rectangle, setWidth()

{

long width;

if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “l”, &width) == FAILURE){

WRONG_PARAM_COUNT;

}

if( width <= 0 ) {

width = 1;

}

zend_update_property_long(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_width”), width TSRMLS_CC); //更新类成员变量_width的值

RETURN_TRUE;

}

PHP_METHOD(Rectangle, setHeight()

{

long height;

if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “l”, &height) == FAILURE){

WRONG_PARAM_COUNT;

}

if( height <= 0 ) {

height = 1;

}

zend_update_property_long(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_height”), height TSRMLS_CC); //更新类成员变量_height的值

RETURN_TRUE;

}

PHP_METHOD(Rectangle, getWidth)

{

zval *zWidth;

long width;

zWidth = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_width”), 0 TSRMLS_CC); //获取类成员变量_width的值

width = Z_LVAL_P(zWidth);

RETURN_LONG(width);

}

PHP_METHOD(Rectangle, getHeight)

{

zval *zHeight;

long height;

zHeight = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_height”), 0 TSRMLS_CC);

height = Z_LVAL_P(zHeight);

RETURN_LONG(height);

}

PHP_METHOD(Rectangle, getArea)

{

zval *zWidth,*zHeight;

long width,height,area;

zWidth = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_width”), 0 TSRMLS_CC);

zHeight = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_height”), 0 TSRMLS_CC);

width = Z_LVAL_P(zWidth);

height = Z_LVAL_P(zHeight);

area = width * height;

RETURN_LONG(area);

}

PHP_METHOD(Rectangle, getCircle)

{

zval *zWidth,*zHeight;

long width,height,circle;

zWidth = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_width”), 0 TSRMLS_CC);

zHeight = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL(“_height”), 0 TSRMLS_CC);

width = Z_LVAL_P(zWidth);

height = Z_LVAL_P(zHeight);

circle = (width + height) * 2;

RETURN_LONG(circle);

}

4. 编译代码

cd php-5.2.8/ext/class_ext

/usr/local/php/bin/phpize

./configure –with-php-config=/usr/local/php/bin/php-config

make

make install

此时会在php的安装路径下产生一个so文件,比如

/usr/local/php/lib/php/extensions/no-debug-non-zts-20060613/class_ext.so

修改php.ini 添加扩展

extension_dir = “/usr/local/php/lib/php/extensions/no-debug-non-zts-20060613/”

[class_ext]

extension = class_ext.so

5. 测试代码

$width = -10;

$height = 12;

$rectangle = new Rectangle($width, $height);

$area = $rectangle->getArea();

var_dump($area);

$circle = $rectangle->getCircle();

var_dump($circle);

$clone = $rectangle->clone();

$_area = $clone->getArea();

var_dump($_area);

$clone->setWidth(100);

$clone->setHeight(200);

$_area = $clone->getArea();

var_dump($_area);

$width = $clone->getWidth();

var_dump($width);

$height = $clone->getHeight();

var_dump($height);

结果输出:

int(12)

int(26)

int(12)

int(20000)

int(100)

int(200)

6. Over!