[英]C++ Object Oriented PHP Extension
在http://devzone.zend.com/article/4486教程之后,我嘗試將幾個 C++ 類包裝到 PHP 擴展中,不幸的是它失敗了, 我希望有人可以幫助我。 為了嘗試簡化問題解決,我還簡化了我的課程。
目標是擁有允許我執行一些多邊形操作的類。 然后我創建了點 class 和多邊形 class 如下:
多邊形.h
#ifndef POLYGON_H
#define POLYGON_H 1
#include <vector>
class Point {
double __x;
double __y;
public:
Point(double x, double y);
double x(void);
double y(void);
};
class Polygon {
std::vector<Point> __pts;
public:
void add(Point pnt);
Point& get(unsigned long idx);
unsigned long size(void);
};
#endif
多邊形.cpp
#include "polygon.h"
Point::Point(double x, double y) : __x(x), __y(y) {
}
double Point::x(void) {
return __x;
}
double Point::y(void) {
return __y;
}
void Polygon::add(Point pnt) {
__pts.push_back(pnt);
}
Point& Polygon::get(unsigned long idx) {
return __pts.at(idx);
}
unsigned long Polygon::size(void) {
return __pts.size();
}
配置.m4
PHP_ARG_ENABLE(geometry,
[Whether to enable the "geometry" extension],
[ --enable-geometry Enable "geometry" extension support])
if test $PHP_GEOMETRY != "no"; then
PHP_REQUIRE_CXX()
PHP_SUBST(GEOMETRY_SHARED_LIBADD)
PHP_ADD_LIBRARY(stdc++, 1, GEOMETRY_SHARED_LIBADD)
PHP_NEW_EXTENSION(geometry, geometry.cpp polygon.cpp, $ext_shared)
fi
php_geometry.h
#ifndef PHP_GEOMETRY_H
#define PHP_GEOMETRY_H 1
#define PHP_GEOMETRY_EXTNAME "geometry"
#define PHP_GEOMETRY_EXTVER "0.1"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
extern "C" {
#include "php.h"
}
extern zend_module_entry geometry_module_entry;
#define phpext_geometry_ptr &geometry_module_entry;
PHP_METHOD(Point, __construct);
PHP_METHOD(Point, x);
PHP_METHOD(Point, y);
PHP_METHOD(Polygon, __construct);
PHP_METHOD(Polygon, add);
PHP_METHOD(Polygon, get);
PHP_METHOD(Polygon, size);
#endif
幾何圖形.cpp
#include "php_geometry.h"
#include "polygon.h"
zend_object_handlers point_object_handlers;
zend_object_handlers polygon_object_handlers;
struct point_object {
zend_object std;
Point* point;
};
struct polygon_object {
zend_object std;
Polygon* polygon;
};
zend_class_entry* point_ce;
zend_class_entry* polygon_ce;
void point_free_storage(void* object TSRMLS_DC) {
point_object* obj = (point_object*)object;
delete obj->point;
zend_hash_destroy(obj->std.properties);
FREE_HASHTABLE(obj->std.properties);
efree(obj);
}
void polygon_free_storage(void* object TSRMLS_DC) {
polygon_object* obj = (polygon_object*)object;
delete obj->polygon;
zend_hash_destroy(obj->std.properties);
FREE_HASHTABLE(obj->std.properties);
efree(obj);
}
zend_object_value point_create_handler(zend_class_entry* type TSRMLS_DC) {
zval* tmp;
zend_object_value retval;
point_object* obj = (point_object*)emalloc(sizeof(point_object));
memset(obj, 0, sizeof(point_object));
obj->std.ce = type;
ALLOC_HASHTABLE(obj->std.properties);
zend_hash_init(obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
zend_hash_copy(obj->std.properties, &type->default_properties, (copy_ctor_func_t)zval_add_ref, (void*)&tmp, sizeof(zval*));
retval.handle = zend_objects_store_put(obj, NULL,
point_free_storage, NULL TSRMLS_CC);
retval.handlers = &point_object_handlers;
return retval;
}
zend_object_value polygon_create_handler(zend_class_entry* type TSRMLS_DC) {
zval* tmp;
zend_object_value retval;
polygon_object* obj = (polygon_object*)emalloc(sizeof(polygon_object));
memset(obj, 0, sizeof(polygon_object));
obj->std.ce = type;
ALLOC_HASHTABLE(obj->std.properties);
zend_hash_init(obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
zend_hash_copy(obj->std.properties, &type->default_properties, (copy_ctor_func_t)zval_add_ref, (void*)&tmp, sizeof(zval*));
retval.handle = zend_objects_store_put(obj, NULL,
polygon_free_storage, NULL TSRMLS_CC);
retval.handlers = &polygon_object_handlers;
return retval;
}
function_entry point_methods[] = {
PHP_ME(Point, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Point, x, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Point, y, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
function_entry polygon_methods[] = {
PHP_ME(Polygon, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Polygon, add, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Polygon, get, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Polygon, size, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
PHP_MINIT_FUNCTION(geometry) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Point", point_methods);
point_ce = zend_register_internal_class(&ce TSRMLS_CC);
point_ce->create_object = point_create_handler;
memcpy(&point_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
point_object_handlers.clone_obj = NULL;
INIT_CLASS_ENTRY(ce, "Polygon", polygon_methods);
polygon_ce = zend_register_internal_class(&ce TSRMLS_CC);
polygon_ce->create_object = polygon_create_handler;
memcpy(&polygon_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
polygon_object_handlers.clone_obj = NULL;
return SUCCESS;
}
zend_module_entry geometry_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_GEOMETRY_EXTNAME,
NULL, /* Functions */
PHP_MINIT(geometry), /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
PHP_GEOMETRY_EXTVER,
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_GEOMETRY
extern "C" {
ZEND_GET_MODULE(geometry)
}
#endif
PHP_METHOD(Point, __construct) {
double x = .0;
double y = .0;
zval *object = getThis();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|dd", &x, &y) == FAILURE)
RETURN_NULL();
point_object *obj = (point_object *)zend_object_store_get_object(object TSRMLS_CC);
obj->point = new Point(x, y);
}
PHP_METHOD(Point, x) {
point_object *obj = (point_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
Point *point = obj->point;
if(point != NULL)
RETURN_DOUBLE(point->x());
}
PHP_METHOD(Point, y) {
point_object *obj = (point_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
Point *point = obj->point;
if(point != NULL)
RETURN_DOUBLE(point->y());
}
PHP_METHOD(Polygon, __construct) {
zval* object = getThis();
polygon_object* obj = (polygon_object*)zend_object_store_get_object(object TSRMLS_CC);
obj->polygon = new Polygon;
}
PHP_METHOD(Polygon, add) {
polygon_object *obj = (polygon_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
Polygon *polygon = obj->polygon;
if(polygon != NULL) {
zval* oth;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &oth, point_ce) == FAILURE)
RETURN_NULL();
point_object* ooth = (point_object*)zend_object_store_get_object(oth TSRMLS_CC);
polygon->add(*ooth->point);
}
}
PHP_METHOD(Polygon, get) {
polygon_object *obj = (polygon_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
Polygon *polygon = obj->polygon;
if(polygon != NULL) {
long index;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == FAILURE)
RETURN_NULL();
if (object_init_ex(return_value, point_ce) != SUCCESS) {
} else {
struct point_object* vobj = (struct point_object *) zend_object_store_get_object(return_value TSRMLS_CC);
assert (vobj != NULL);
vobj->point = &polygon->get(index);
}
}
}
PHP_METHOD(Polygon, size) {
polygon_object *obj = (polygon_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
Polygon *polygon = obj->polygon;
if(polygon != NULL)
RETURN_LONG(polygon->size());
}
然后,編譯后我嘗試以下 PHP 代碼:
<?php
echo '<pre>';
$pt = new Point;
var_dump($pt);
$pl = new Polygon;
$pl->add($pt);
$pl->add(new Point(10, 0));
$pl->add(new Point(10, 10));
for($i = 0; $i < $pl->size(); $i++)
var_dump($pl->get($i));
?>
執行 Polygon::get 方法時總是崩潰,如果我評論它,不會發生任何錯誤。
Valgrind 給了我這個:
==14188== Invalid free() / delete / delete[]
==14188== at 0x4C27A83: operator delete(void*) (vg_replace_malloc.c:387)
==14188== by 0xE1C3D7C: point_free_storage(void*) (geometry.cpp:24)
所以,在某些時候,這條線:
delete obj->point;
... 在obj->point
不是實際指針時執行。 刪除delete
調用很可能也會刪除錯誤(盡管很可能會發生泄漏,因為obj->point
在某些情況下將是一個指針)。
據我所知, Polygon::get
不返回指針,而是返回引用。 因為它不是一個指針,所以在它上面調用delete
會給你一個Invalid free()
錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.