將 C++ 類封裝為 PHP 擴展能充分利用 C++ 生態與 OOP 優勢。本文基於 Zend 官方教程,詳細記錄 vehicles 擴展開發全過程,涵蓋配置、類定義、對象處理器、生命周期管理、方法映射等核心環節。
vehicles/ ├── config.m4 # 擴展配置 ├── php_vehicles.h # 擴展頭文件 ├── vehicles.cc # 擴展核心實現 ├── car.h # C++ 類聲明 └── car.cc # C++ 類實現
PHP_ARG_ENABLE(vehicles,
[Whether to enable the "vehicles" extension],
[ --enable-vehicles Enable "vehicles" extension support])
if test $PHP_VEHICLES != "no"; then
PHP_REQUIRE_CXX() # 需 C++ 編譯器
PHP_SUBST(VEHICLES_SHARED_LIBADD) # 動態鏈接庫標記
PHP_ADD_LIBRARY(stdc++, 1, VEHICLES_SHARED_LIBADD) # 鏈接 C++ 標準庫
PHP_NEW_EXTENSION(vehicles, vehicles.cc car.cc, $ext_shared) # 包含所有源文件
fi
PHP_REQUIRE_CXX():強制使用 C++ 編譯器PHP_ADD_LIBRARY(stdc++):鏈接 C++ 標準庫,支援 string、STL 等PHP_NEW_EXTENSION:必須包含 所有 .cc 源文件// car.h
#ifndef VEHICLES_CAR_H
#define VEHICLES_CAR_H
class Car {
public:
Car(int maxGear);
void shift(int gear);
void accelerate();
void brake();
int getCurrentSpeed();
int getCurrentGear();
private:
int maxGear, currentGear, speed;
};
#endif
// car.cc
#include "car.h"
Car::Car(int maxGear) : maxGear(maxGear), currentGear(1), speed(0) {}
void Car::shift(int gear) {
if (gear < 1 || gear > maxGear) return;
currentGear = gear;
}
void Car::accelerate() { speed += 5 * currentGear; }
void Car::brake() { speed -= 5 * currentGear; }
int Car::getCurrentSpeed() { return speed; }
int Car::getCurrentGear() { return currentGear; }
#ifndef PHP_VEHICLES_H
#define PHP_VEHICLES_H
#define PHP_VEHICLES_EXTNAME "vehicles"
#define PHP_VEHICLES_EXTVER "0.1"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
extern "C" { // 關鍵:PHP 內核是 C 語言
#include "php.h"
}
extern zend_module_entry vehicles_module_entry;
#define phpext_vehicles_ptr &vehicles_module_entry
#endif
extern "C":解決 C++ 名稱修飾問題,確保 Zend 能正確鏈接符號#include "php_vehicles.h"
PHP_MINIT_FUNCTION(vehicles) { return SUCCESS; }
zend_module_entry vehicles_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_VEHICLES_EXTNAME,
NULL, // Functions(此處為類方法,非全局函數)
PHP_MINIT(vehicles), // MINIT
NULL, NULL, NULL, NULL, // MSHUTDOWN, RINIT, RSHUTDOWN, MINFO
#if ZEND_MODULE_API_NO >= 20010901
PHP_VEHICLES_EXTVER,
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_VEHICLES
extern "C" { ZEND_GET_MODULE(vehicles) }
#endif
#include "php_vehicles.h"
zend_class_entry *car_ce; // 類入口指針
// 方法聲明
PHP_METHOD(Car, __construct);
PHP_METHOD(Car, shift);
PHP_METHOD(Car, accelerate);
PHP_METHOD(Car, brake);
PHP_METHOD(Car, getCurrentSpeed);
PHP_METHOD(Car, getCurrentGear);
// 方法表
zend_function_entry car_methods[] = {
PHP_ME(Car, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Car, shift, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Car, accelerate, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Car, brake, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Car, getCurrentSpeed, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Car, getCurrentGear, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
PHP_MINIT_FUNCTION(vehicles) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Car", car_methods); // 初始化類入口
car_ce = zend_register_internal_class(&ce TSRMLS_CC); // 註冊到類表
return SUCCESS;
}
#include "car.h"
zend_object_handlers car_object_handlers;
struct car_object {
zend_object std; // 嵌入標準對象
Car *car; // C++ 實例指針
};
// 釋放存儲
void car_free_storage(void *object TSRMLS_DC) {
car_object *obj = (car_object *)object;
delete obj->car; // 刪除 C++ 實例
zend_hash_destroy(obj->std.properties); // 銷毀屬性表
FREE_HASHTABLE(obj->std.properties);
efree(obj); // 釋放對象結構
}
// 創建處理器
zend_object_value car_create_handler(zend_class_entry *type TSRMLS_DC) {
zval *tmp;
zend_object_value retval;
car_object *obj = (car_object *)emalloc(sizeof(car_object));
memset(obj, 0, sizeof(car_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, car_free_storage, NULL TSRMLS_CC);
retval.handlers = &car_object_handlers;
return retval;
}
PHP_MINIT_FUNCTION(vehicles) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Car", car_methods);
car_ce = zend_register_internal_class(&ce TSRMLS_CC);
car_ce->create_object = car_create_handler; // 關鍵:綁定創建處理器
// 複製標準處理器並禁用 clone
memcpy(&car_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
car_object_handlers.clone_obj = NULL;
return SUCCESS;
}
PHP_METHOD(Car, __construct) {
long maxGear;
Car *car = NULL;
zval *object = getThis();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &maxGear) == FAILURE) {
RETURN_NULL();
}
car = new Car(maxGear); // 創建 C++ 實例
car_object *obj = (car_object *)zend_object_store_get_object(object TSRMLS_CC);
obj->car = car; // 綁定到 PHP 對象
}
PHP_METHOD(Car, accelerate) {
car_object *obj = (car_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
if (obj->car) obj->car->accelerate();
}
PHP_METHOD(Car, getCurrentSpeed) {
car_object *obj = (car_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
if (obj->car) RETURN_LONG(obj->car->getCurrentSpeed());
RETURN_NULL();
}
// shift、brake、getCurrentGear 同理...
phpize ./configure --enable-vehicles make sudo make install # php.ini 添加 extension=vehicles.so # 重啟 Apache
<?php $car = new Car(5); // 5 擋車 echo $car->getCurrentSpeed(); // 0 $car->accelerate(); echo $car->getCurrentSpeed(); // 5 ?>
輸出 0 和 5 即成功。此模式可擴展至任意 C++ 類封裝,是高效能 PHP 擴展開發的核心範式。