Building PHP extensions with C the easy way
Here is an easy way to build a PHP extension with C++ and default PHP packages on a Ubuntu system. I use SWIG to wrap C++ code to the Zend API. When using loops and recursion intensively, porting a few functions to C++ can give you some extra power.
First, install all required packages (tested with Ubuntu 12.10):
apt-get install php5-cli php5-dev swig g++
Second, write the code:
// example.swig %{ #include #include using namespace std; int HelloWorld(char *str) { cout << "Hello World: " << str << endl; // run some slow code vector array; for (int i=0; i < 10000000; i++) array.push_back(i*2); for (int i=0; i < array.size(); i++) array[i]++; return 0; } %} %module example int HelloWorld(char *str);
Third, compile the code and load the exension:
swig -c++ -php5 example.swig g++ `php-config --includes` -O2 -march=native -mtune=native -std=c++11 -fPIC -c *.cpp g++ -shared *.o -o example.so echo extension=`pwd`/example.so >/etc/php5/mods-available/example.ini php5enmod example
And finally run: php test.php
// test.php HelloWorld("C++"); // gives: Hello World: C++ HelloWorld("foobar"); // gives: Hello World: foo
Note: To send the output to a web server, zend_printf()
needs be used instead of std::cout
or printf()
.
You can also start Threads from an extension (C++11 is really nice here):
// example.swig %{ #include #include #include using namespace std; void someThread(int i) { for (int j=0; j < 100; j++) { cout << " thread: " << i << endl ; vector array; for (int i=0; i < 10000000; i++) array.push_back(i*2); for (int i=0; i < array.size(); i++) array[i] *= 2; } } int HelloWorld(char *str) { cout << "Hallo World: " << str << endl; // start some threads thread t1(someThread, 1); thread t2(someThread, 2); thread t3(someThread, 3); // wait for threads to finish t1.join(); t2.join(); t3.join(); return 0; } %} %module example int HelloWorld(char *str);
A small MySQL example looks like this:
// apt-get install mysql-server-5.5 libmysqlcppconn-dev // g++ -shared *.o -lmysqlcppconn -o example.so // example.swig %{ #include #include <cppconn/driver.h> #include <cppconn/statement.h> #include <cppconn/resultset.h> #include <cppconn/exception.h> #include "mysql_connection.h" using namespace std; using namespace sql; int HelloWorld(char *str) { try { auto_ptr con( get_driver_instance()->connect("127.0.0.1", "root", "") ); con->setSchema("test"); auto_ptr stmt( con->createStatement() ); auto_ptr res( stmt->executeQuery("SELECT 'Hello World!' AS result") ); while (res->next()) { cout << res->getString("result") << endl; cout << res->getString(1) << endl; } } catch (SQLException &e) { cout << __FILE__ << " " << __FUNCTION__ << " " << __LINE__ << endl; cout << e.what() << " " << e.getSQLState() << " " << e.getErrorCode() << endl; } return 0; } %} %module example int HelloWorld(char *str);