C での PHP 拡張クラスの実装
C 言語で PHP 拡張を実装する手順は、C で PHP 拡張を開発する手順を参照してください。ここでは、関数を拡張する方法について説明します。 C を使用してクラスを拡張します。
実装するクラスは以下のとおりです。
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
cd php-5.2.8/ext/class_ext vi config.m4
[ --enable-class_ext class_ext サポートを有効にする]) 2 行の前の 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])
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
/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.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)