Speedup your PHP with C extension

PHP C extension

Prelude

Nowadays we know a lot of PHP extensions like Phalcon or Swoole. But does it make sens to build them? That's the main question. To find out, we need to build at least one. So, let's do it!

Stage 1: prepare environment

To achieve maximum performance we'll use only standard API for building our extension. That's mean that we need to learn some basics not only about C language, but also about PHP API extensions.

The one (and probably only one) guide is www.phpinternalsbook.com. Unfortunately, lots of articles about PHP7 API are missing. But if you're brave enough and got some experience with C, this will not stop you on your way to build PHP7 extension.

The target for our extension will be Linux. Since I'm a web engineer, I work on Linux most of the time. But when I'm at home I prefer to use more convenient for me Windows. You might know, that if you want to build some program for certain platform, you need to build it on this exact platform. That's why we'll use Docker. This will allow us to work with our project on any platform you prefer.

In this example we'll eventually build complete analog of Lumen-like routes

Clone ready to develop repository. Let's see how it's done.

Dockerfile

These instructions will add all necessary dependencies for building our extension, then clone source repository of PHP, then choose PHP version 7.3.6, and finally build it with -j4 = four parallel processes just to not waste the time.

Then open cmd or powershell in current directory and build image:

docker build -t php_ext:latest .

Stage 2: initial setup

Every time you need to build / compile your project you need to enter container using:

docker run --rm --name php_ext -v d:/projects/php_extensions/router/src:/src -it php_ext sh.

Please make note that you have to change directory according to your system.

This command used only once to create all necessary files for project:

/usr/local/php7/bin/phpize && ./configure --with-php-config=/usr/local/php7/bin/php-config

This command will build your extension, clean up binaries and execute tests

make && make clean && make test && make install

Stage 3: Extension

Now let's take a closer look to the code.

First of all, since we're using regular expressions, we'll add check for external dependency in config.m4 via AC_CHECK_HEADER

Our extension has its own class and methods that should return self-instance. That's why in header-file we have to add very useful template:

Be careful with arguments in methods! Make sure that you're not assigning them to global variables. PHP engine will reduce usage and probably will reuse them next time. So once you've received parameter, copy its value to another variable. Or if you need to work with it later - better to use heap. But do not forget to free memory then! Otherwise you'll have memory leak.

Stage 4: comparision & conclusion

We've used scripts that run both approaches with 999 instances of Class 100 times.

Tests were made on Aser Aspire E15 (AMD A10) within docker container

Regular PHP Class PHP Extension (C implementation)
Time in seconds 1.787871599197389 1.473563671112060
Overall 1.21 times slower 1.21 times faster

The answer to the main question will be: you can increase performance up to 21%. But you will probably spend much more time to implement the same functionality.