用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
2,修改編譯參數
cd php-5.2.8/ext/class_extvi 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_extvi 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-configmake 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!