How fast is a C++ extension

Native extensions are fast. But how fast are they? We can demonstrate this with a very simple extension: bubblesort.

Bubblesort is a very inefficient sorting algorithm that is never used in real world software - but that is often used in universities to demonstrate algorithms. We will show you an implementation of this algorithm in PHP and in C++ - and see how much faster the C++ code is.


<?php
/**
 *  Bubblesort function in PHP
 *
 *  This function takes an unsorted array as input, sorts it, and returns
 *  the output. It only uses normal PHP operation, and does not rely on
 *  any builtin PHP functions or on functions from extensions
 *
 *  @param  array       An unsorted array of integers
 *  @return array       A sorted array
 */
function scripted_bubblesort(array $input)
{
    // number of elements in the array
    $count = count($input);
    
    // loop through the array
    for ($i = 0; $i < $count; $i++)
    {
        // loop through the elements that were already processed
        for ($j = 1; $j < $count - $i; $j++)
        {
            // move on if smaller
            if ($input[$j-1] <= $input[$j]) continue;
    
            // swap elements
            $temp = $input[$j];
            $input[$j] = $input[$j-1];
            $input[$j-1] = $temp;
        }
    }
}
?>

And exactly the same algorithm in C++:


#include <phpcpp.h>

/**
 *  Bubblesort function in C++
 *
 *  This function takes an unsorted array as input, sorts it, and returns
 *  the output. Notice that we have not really done our best to make the
 *  implementation of this function as efficient as possible - we use stl
 *  containers for example - it is simple looking plain C++ function with
 *  a lot of room for improvements.
 *
 *  @param  array       An unsorted array of integers
 *  @return array       A sorted array
 */
Php::Value native_bubblesort(Php::Parameters ¶ms)
{
    // there is one input array, cast the PHP variable to a vector of ints
    std::vector<int> input = params[0];
    
    // loop through the array
    for (size_t i = 0; i < input.size(); i++)
    {
        // loop through the elements that were already processed
        for (size_t j = 1; j < input.size() - i; j++)
        {
            // move on if smaller
            if (input[j-1] <= input[j]) continue;
    
            // swap elements
            temp = input[j];
            input[j] = input[j-1];
            input[j-1] = temp;
        }
    }
}

/**
 *  Switch to C context, because the Zend-engine calls the get_module() method
 *  in C context, and not in C++ context
 */
extern "C" {
    
    /**
     *  When a PHP extension starts up, the Zend engine calls the get_module()
     *  function to find out which functions and classes are offered by the 
     *  extension
     *
     *  @return void*   pointer to memory address holding the extension information
     */
    PHPCPP_EXPORT void *get_module() 
    {
        // create an instance of the Php::Extension class
        static Php::Extension extension("bubblesort", "1.0");
        
        // add the bubblesort function to the extension, we also tell the 
        // extension that the function receives one parameter by value, and
        // that that parameter must be an array
        extension.add("native_bubblesort", native_bubblesort, { 
            ByVal("input", Php::Type::Array)
        });
        
        // return the extension
        return extension;
    }
}

You may be surprised how simple the C++ function looks. It is almost identical to the PHP code. That's true indeed, writing native extensions with PHP-CPP is simple, and you can easily port your PHP functions to C++.

You also see an additional get_module() function in the extension call. This is the startup function that is called by the Zend engine when PHP starts up. It is supposed to return information to the Zend engine about the extension, so that the "native_bubblesort" function is accessible for PHP scripts.