Home > Article > Backend Development > PHP extension and embedding--Extension development of c++ classes_PHP tutorial
Today I spent almost a day studying related C++ extensions of PHP. When I first came into contact with them, I was not familiar with many places and encountered many pitfalls. The whole process is described here as follows. The reference articles are mainly http://devzone .zend.com/1435/wrapping-c-classes-in-a-php-extension/:
Now a Car class is defined, which has some member functions. The files included in the entire extension are as follows:
1 PHP_ARG_ENABLE(vehicles, 2 [Whether to enable the "vehicles" extension], 3 [ --enable-vehicles Enable "vehicles" extension support]) 4 5 if test $PHP_VEHICLES != "no"; then 6 PHP_REQUIRE_CXX() 7 PHP_SUBST(VEHICLES_SHARED_LIBADD) 8 PHP_ADD_LIBRARY(stdc++, 1, VEHICLES_SHARED_LIBADD) 9 PHP_NEW_EXTENSION(vehicles, vehicles.cc car.cc, $ext_shared) 10 fi
#ifndef VEHICLES_CAR_H 2 #define VEHICLES_CAR_H 3 4 // A very simple car class 5 class Car { 6 public: 7 Car(int maxGear); 8 void shift(int gear); 9 void accelerate(); 10 void brake(); 11 int getCurrentSpeed(); 12 int getCurrentGear(); 13 private: 14 int maxGear; 15 int currentGear; 16 int speed; 17 }; 18 19 #endif /* VEHICLES_CAR_H */This is exactly the same as the C++ header file declaration. The source file of the class car.cc The source file is also a class definition of C++.
2 #include "car.h" 3 Car::Car(int maxGear) { 4 this->maxGear = maxGear; 5 this->currentGear = 1; 6 this->speed = 0; 7 } 9 void Car::shift(int gear) { 10 if (gear < 1 || gear > maxGear) { 11 return; 12 } 13 currentGear = gear; 14 } 16 void Car::accelerate() { 17 speed += (5 * this->getCurrentGear()); 18 } 20 void Car::brake() { 21 speed -= (5 * this->getCurrentGear()); 22 } 24 int Car::getCurrentSpeed() { 25 return speed; 26 }
1 #ifndef PHP_VEHICLES_H 2 #define PHP_VEHICLES_H 4 #define PHP_VEHICLES_EXTNAME "vehicles" 5 #define PHP_VEHICLES_EXTVER "0.1" 7 #ifdef HAVE_CONFIG_H 8 #include "config.h" 9 #endif 10 11 extern "C" { 12 #include "php.h" 13 } 14 15 extern zend_module_entry vehicles_module_entry; 16 #define phpext_vehicles_ptr &vehicles_module_entry; 17 18 #endif /* PHP_VEHICLES_H */First, use a macro to determine whether the header file has been included. Then give the extension an alias on the fourth line. The version number is given on the fifth line. Note that lines 11 to 13 are included with extern "C". This is because PHP is written in C, so it must be declared when developing a C++ extension. Line 15 declares the entry of the entire extension module. In this entry function, startup functions such as MINITRINIT and shutdown functions such as MSHUTDOWN RSHUTDOWN will be defined. The source file of php extension vehicles.cc: There is quite a lot of content in this file, because it carries the task of how to connect the C++ classes we want with the PHP kernel. At the same time, the member functions in the class also need to be mapped accordingly in this file for convenience PHP can be called directly. These functions will be explained one by one in the source code below: In the first stage of the code, we will not cover the class-related parts first, but proceed step by step. The code here first gives some operations that need to be performed in the conventional PHP extension source code:
1 #include "php_vehicles.h" 2 PHP_MINIT_FUNCTION(vehicles) 3 { 4 return SUCCESS; 5 } 6 zend_module_entry vehicles_module_entry = { 7 #if ZEND_MODULE_API_NO >= 20010901 8 STANDARD_MODULE_HEADER, 9 #endif 10 PHP_VEHICLES_EXTNAME, 11 NULL, /* Functions */ 12 PHP_MINIT(vehicles), 13 NULL, /* MSHUTDOWN */ 14 NULL, /* RINIT */ 15 NULL, /* RSHUTDOWN */ 16 NULL, /* MINFO */ 17 #if ZEND_MODULE_API_NO >= 20010901 18 PHP_VEHICLES_EXTVER, 19 #endif 20 STANDARD_MODULE_PROPERTIES 21 }; 22 #ifdef COMPILE_DL_VEHICLES 23 extern "C" { 24 ZEND_GET_MODULE(vehicles) 25} 26 #endif
1 #include "php_vehicles.h" 2 zend_class_entry *car_ce; 3 PHP_METHOD(Car, __construct){} 5 PHP_METHOD(Car, shift) {} 7 PHP_METHOD(Car, accelerate) {} 9 PHP_METHOD(Car, brake) {} 11 PHP_METHOD(Car, getCurrentSpeed){} 13 PHP_METHOD(Car, getCurrentGear){} 15 zend_function_entry car_methods[] = { 16 PHP_ME(Car, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) 17 PHP_ME(Car, shift, NULL, ZEND_ACC_PUBLIC) 18 PHP_ME(Car, accelerate, NULL, ZEND_ACC_PUBLIC) 19 PHP_ME(Car, brake, NULL, ZEND_ACC_PUBLIC) 20 PHP_ME(Car, getCurrentSpeed, NULL, ZEND_ACC_PUBLIC) 21 PHP_ME(Car, getCurrentGear, NULL, ZEND_ACC_PUBLIC) 22 {NULL, NULL, NULL} 23 }; 24 PHP_MINIT_FUNCTION(vehicles) 25 { 26 zend_class_entry ce; 27 INIT_CLASS_ENTRY(ce, "Car", car_methods); 28 car_ce = zend_register_internal_class(&ce TSRMLS_CC); 29 return SUCCESS; 30 } 31 zend_module_entry vehicles_module_entry = { 32 #if ZEND_MODULE_API_NO >= 20010901 33 STANDARD_MODULE_HEADER, 34 #endif 35 PHP_VEHICLES_EXTNAME, 36 NULL, /* Functions */ 37 PHP_MINIT(vehicles), /* MINIT */ 38 NULL, /* MSHUTDOWN */ 39 NULL, /* RINIT */ 40 NULL, /* RSHUTDOWN */ 41 NULL, /* MINFO */ 42 #if ZEND_MODULE_API_NO >= 20010901 43 PHP_VEHICLES_EXTVER, 44 #endif 45 STANDARD_MODULE_PROPERTIES 46 }; 47 #ifdef COMPILE_DL_VEHICLES 48 extern "C" { 49 ZEND_GET_MODULE(vehicles) 50 } 51 #endif
1 #include "car.h" 2 zend_object_handlers car_object_handlers; 3 struct car_object { 4 zend_object std; 5 Car *car; 6 };
1 void car_free_storage(void *object TSRMLS_DC) 2 { 3 car_object *obj = (car_object *)object; 4 delete obj->car; 5 zend_hash_destroy(obj->std.properties); 6 FREE_HASHTABLE(obj->std.properties); 7 efree(obj); 8 } 9 zend_object_value car_create_handler(zend_class_entry *type TSRMLS_DC) 10 { 11 zval *tmp; 12 zend_object_value retval; 13 car_object *obj = (car_object *)emalloc(sizeof(car_object)); 14 memset(obj, 0, sizeof(car_object)); 15 obj->std.ce = type; 16 ALLOC_HASHTABLE(obj->std.properties); 17 zend_hash_init(obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0); 18 zend_hash_copy(obj->std.properties, &type->default_properties, 19 (copy_ctor_func_t)zval_add_ref, (void *)&tmp, sizeof(zval *)); 20 retval.handle = zend_objects_store_put(obj, NULL, 21 car_free_storage, NULL TSRMLS_CC); 22 retval.handlers = &car_object_handlers; 23 return retval; 24 }
25 PHP_MINIT_FUNCTION(vehicles) 26 { 27 zend_class_entry ce; 28 INIT_CLASS_ENTRY(ce, "Car", car_methods); 29 car_ce = zend_register_internal_class(&ce TSRMLS_CC); 30 car_ce->create_object = car_create_handler; 31 memcpy(&car_object_handlers, 32 zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 33 car_object_handlers.clone_obj = NULL; 34 return SUCCESS; 35}
1 PHP_METHOD(Car, __construct) 2 { 3 long maxGear; 4 Car *car = NULL; 5 zval *object = getThis(); 6 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &maxGear) == FAILURE) { 7 RETURN_NULL(); 8 } 9 car = new Car(maxGear); 10 car_object *obj = (car_object *)zend_object_store_get_object(object TSRMLS_CC); 11 obj->car = car; 12 }
PHP_METHOD(accelerate) { Car *car; car_object *obj = (car_object *)zend_object_store_get_object( getThis() TSRMLS_CC); car = obj->car; if (car != NULL) { car->accelerate(); } } PHP_METHOD(getCurrentSpeed) { Car *car; car_object *obj = (car_object *)zend_object_store_get_object( getThis() TSRMLS_CC); car = obj->car; if (car != NULL) { RETURN_LONG(car->getCurrentSpeed()); } RETURN_NULL(); }
<pre class="code">/ create a 5 gear car $car = new Car(5); print $car->getCurrentSpeed(); // prints '0' $car->accelerate(); print $car->getCurrentSpeed(); // prints '5' If you can run this script, congratulations, you’ve just created a PHP extension that wraps a C++ class.