首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP C++ 類擴展開發實戰:封裝 Car 類完整流程解析

     編輯:PHP 相關知識

前言

將 C++ 類封裝為 PHP 擴展能充分利用 C++ 生態與 OOP 優勢。本文基於 Zend 官方教程,詳細記錄 vehicles 擴展開發全過程,涵蓋配置、類定義、對象處理器、生命周期管理、方法映射等核心環節。

一、項目結構

vehicles/
├── config.m4          # 擴展配置
├── php_vehicles.h     # 擴展頭文件
├── vehicles.cc        # 擴展核心實現
├── car.h              # C++ 類聲明
└── car.cc             # C++ 類實現

二、配置文件 config.m4

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 源文件

三、C++ 類定義(car.h / car.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; }

四、擴展頭文件 php_vehicles.h

#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 能正確鏈接符號
  • 模組入口聲明供動態加載使用

五、擴展核心實現 vehicles.cc(分階段構建)

階段一:基礎模組框架

#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

階段二:PHP 類定義與方法映射

#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;
}

階段三:對象處理器——連接 C++ 實例與 PHP 對象

#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;
}

階段四:MINIT 註冊對象處理器

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 測試腳本

<?php
$car = new Car(5);        // 5 擋車
echo $car->getCurrentSpeed(); // 0
$car->accelerate();
echo $car->getCurrentSpeed(); // 5
?>

輸出 0 和 5 即成功。此模式可擴展至任意 C++ 類封裝,是高效能 PHP 擴展開發的核心範式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved