Developing PHP Extensions with C++ and PHP-CPP: Advanced

Share this article

In my earlier articles, I have introduced the PHP-CPP lib to create an extension for PHP using C++ (first article and second article). In the latter, I demonstrated a bit of the OO side of writing a PHP extension with a Complex class doing complex number manipulations.

That introduction is not complete as the main focus of that article is more on the demonstration of the OO capability of PHP-CPP, not on the OO implementation details.

In this article, we will further drill down the Complex lib development, adding more member functions, and addressing some advanced topics in writing a PHP extension with OO features using PHP-CPP:

  • Returning this pointer;
  • Returning a Complex object pointer, i.e., a Complex *;
  • Exposing the __toString magic method;
  • Chaining member function calls;
  • Throwing an exception and handling it in PHP

The finished Complex lib source, as well as a test PHP script is located in this Github repo.

Let’s get started.

Preparations

The entire process of preparing your environment is explained in the first post.

Returning this pointer in C++

As described in the second post, we are using member functions to perform various mathematical operations on complex numbers. In this demo, we will implement four of such functions: add, sub, mul and div. I will explain the first three first. The div function involves exception handling and will be discussed later.

Let’s take a look a the mul function (for multiplication). add and sub functions are more or less the same.

Php::Value add(Php::Parameters &params) {
        Php::Value t = params[0];
        Complex *a = (Complex *) t.implementation();

        r += (double) a->getReal();
        i += (double) a->getImage();

        return this;
    }

NOTE: In this article, I will not cover some previously discussed basic topics, like modifying the Makefile and ini file, registering the member functions, class and namespace, etc. Please refer to the previous parts for those bits.

Returing a this pointer from C++ back to PHP is straightforward. Inside this C++ function, this pointer (as a Complex * type) can be returned back to PHP as a Php::Value type. The conversion won’t lose any object information. It does not require an explicit type conversion either.

Returning a Complex object pointer

Returning this means, most of the time, that the object itself has been changed. But in some cases, we may want to return a new object and keep the “current” object (the calling object) unchanged.

In our Complex class, we have one such function that returns the conjugated number of a given complex number (a+bi becomes a-bi).

Php::Value conjugate() {
        Complex *t = new Complex();

        t->r = r;
        t->i = -i;

        return Php::Object("tr\\Complex", t);
    }

The key point here is that we will have to use Php::Object to explicitly convert our Complex * object into a Php::Object, thus the class information can be properly retained and kept accessible when that object is parsed by a PHP script later.

The first parameter of this function is the class type, in this case tr\\Complex. I use this name as I have wrapped this class (“Complex“) into a separate namespace (“tr“).

The second parameter is the object to be passed back.

Returning a new class instance is a bit trickier than just returning a this pointer but still manageable, as long as you have read through the documentation and found the right section. For some more examples of use, you may want to read this part in PHP-CPP’s official documentation.

Exposing the __toString magical method

In our class, there is a __toString function that prints a complex number in a more readable way like: 1+2i. In my previous article, this function is not exposed (or “registered” in PHP-CPP terms) but still can be called from within PHP. But to make this function callable on the Complex object after we apply some math operations like “echo $a->add($b)->sub($c)“, we need to explicitly register it in our compiled extension:

complex.method("__toString", &Complex::__toString);

The reason we have to do so is discussed in detail in the issue submitted to PHP-CPP repository as Issue #150.

Chaining member function calls

One thing that must be implemented in this class is the ability to chain member functions so that we can do the calculation like: $a->add($b)->sub($c). The result should still be able to call its member functions.

This is done by the approach described above, i.e., returning a this pointer back to PHP. However, older PHP-CPP lib has a bug on dereferencing the object and will create a “Segmentation Fault” if the method calls are chained.

An issue (#151) has been filed and a commit is submitted with the patch on PHP-CPP source. If you are using an older version of PHP-CPP lib to compile the PHP-CPP lib and your own lib, please update the PHP source and re-compile and re-install the PHP-CPP lib and your lib.

As the commit summary explains:

fix issue #151, chaining method calls was not working as it should be…
…cause the per-object refcount was not updated correctly, which caused an object to be destructed even when it already was assigned to a different variable.

I am glad that my work on my own project can help the lib I use become better. [Ed: Well done!]

Exception throwing and handling in PHP

There are two more functions in our Complex class that will probably throw an exception back to PHP to handle: div and phi. The former does a division operation and the latter returns the angle of the complex number as in its alternative representation, the polarized notation (r, θ).

Both operations might fail if a complex number is passed as the parameter (or caller) but its real part and image part are 0. For those two operations, we need to have exception handling. Remember, we are to throw an exception in our C++ code and it is the PHP script that will catch the exception and do the necessary handling:

Php::Value div(Php::Parameters &params) {
        Php::Value t = params[0];
        Complex *b = (Complex*) t.implementation();

        double t1 = b->mod() * b->mod();

        if (t1 < EPS) //EPS is a predefined double value which is very small, say 1E-12
            throw Php::Exception("Division by zero");

        double tr = r * (double) (b->getReal()) + i * (double) (b->getImage());
        double ti = i * (double) (b->getReal()) - r * (double) (b->getImage());

        r = tr / t1;
        i = ti / t1;

        return this;
    }

and in the PHP script, we catch this exception like this:

$a=new tr\Complex(1,2);
$c=new tr\Complex(); //$c is actuall 0+0i

try
{
    $res=$a->div($c);
}
catch(Exception $e)
{
    echo "Caught exception: ".$e->getMessage()."\n";
}
}

The above code segment will display a line of text as below:

Caught exception: Division by zero

Easy, right? A C++ exception constructed inside our extension is passed back to PHP and caught properly. Furthermore, we can manipulate the exception as if it were a native PHP exception thrown by some other PHP code!

Test all the functions

Finally, we can compile and install the complex.so extension for our PHP installation via make && sudo make install. If everything goes smoothly, we can verify the installation of our extension by issuing this command in the terminal:

php -i | grep complex

The terminal should display a line saying “/etc/php5/cli/conf.d/complex.ini” and we can be sure that our extension is installed and ready to be called by any PHP scripts.

NOTE: If we examine the Makefile for this extension, we will see that we are installing this PHP extension into its CLI environment. If we want to install this extension so that it will be loaded by Apache, we change the below line:

# Below is for installation to CLI
#INI_DIR = /etc/php5/cli/conf.d
# Below is for installation to Apache
INI_DIR  = /etc/php5/apache2/conf.d

The testing PHP script for this extension is excerpted below with some comments:

//Testing the mod function
//Displays 5
$c=new tr\Complex(-3,-4);
echo "Mod of $c is: ".$c->mod()."\n";
...
//Testing a string representation of a complex number
//Displays: -4-3i
$e=new tr\Complex(-4,-3);
echo ((string)$e."\n");
...
//Chain the member function calls
$a=new tr\Complex(1,1);
$b=new tr\Complex(1,2);
...
echo ($a->add($b)->sub($c)->add($d))."\n";
...
//Exception handling
$a=new tr\Complex(1,2);
$c=new tr\Complex();

try
{
    $res=$a->div($c);
}
catch(Exception $e)
{
    echo "Caught exception: ".$e->getMessage()."\n";
}

All the test scripts should run correctly and the exceptions are caught properly.

Conclusion

This concludes my 3-article series on this powerful lib to build a PHP extension with C++. We covered the basics, the OO side and some advanced topics in OO programming. We also helped PHP-CPP improve a bit.

What else can we do with PHP-CPP? I will quote a few lines from the email correspondences that I received from Emiel Bruijntjes (co-author of PHP-CPP):

The PHP-CPP library is ideal to use if you’re working on a project, and you have one or more of the following requirements:
– You are working on a piece of software / data structure / algorithm, and you want to ensure that in the future your software can be used in non-PHP projects as well.
– You want to make use of tools or libraries that have not yet been made available as PHP extension.
– You want the better performance of C/C++ code (compared to PHP), but you also want to build structured, object-oriented code, that is easy to understand and easy to maintain for other developers / colleagues.

The possibilities are enormous: a framework (like Phalcon), a template language (like Smarty or Twig), etc.

Please leave your comments and views, and let us know what you have done with this lib!

Frequently Asked Questions (FAQs) on Developing PHP Extensions with C++

What are the benefits of developing PHP extensions with C++?

Developing PHP extensions with C++ offers several benefits. Firstly, it allows you to leverage the power and flexibility of C++ in your PHP applications. This can lead to improved performance, especially for computationally intensive tasks. Secondly, it provides a way to reuse existing C++ code in a PHP environment, which can save significant development time and effort. Lastly, it enables you to create custom PHP extensions that can extend the functionality of PHP and provide features that are not available in the standard PHP library.

How can I get started with PHP extension development using C++?

To get started with PHP extension development using C++, you need to have a basic understanding of both PHP and C++ programming languages. You also need to install the PHP development environment and a C++ compiler. Once you have these prerequisites, you can start writing your PHP extension in C++. There are many resources available online, including tutorials and sample code, that can guide you through the process.

What is PHP-CPP and how does it help in PHP extension development?

PHP-CPP is a library for developing PHP extensions using C++. It provides a set of C++ classes and methods that simplify the process of writing PHP extensions. With PHP-CPP, you can write PHP extensions in a more natural and intuitive way, using the familiar syntax and concepts of C++. This can make the development process more efficient and less error-prone.

Can I use PHP-CPP for commercial projects?

Yes, PHP-CPP is open-source software and can be used for both personal and commercial projects. However, it’s important to understand that while the library itself is free, you may need to invest time and resources in learning how to use it effectively and in maintaining your PHP extensions.

What are some common challenges in PHP extension development with C++ and how can I overcome them?

Some common challenges in PHP extension development with C++ include managing memory correctly, handling errors and exceptions, and interfacing between PHP and C++. These challenges can be overcome by gaining a deep understanding of both PHP and C++, using good programming practices, and leveraging the features and tools provided by PHP-CPP.

How can I debug my PHP extensions written in C++?

Debugging PHP extensions written in C++ can be done using standard C++ debugging tools. Additionally, PHP-CPP provides some features that can help with debugging, such as exception handling and error reporting.

Can I use PHP-CPP with other C++ libraries?

Yes, PHP-CPP can be used with other C++ libraries. This allows you to leverage a wide range of C++ functionality in your PHP extensions.

How can I improve the performance of my PHP extensions written in C++?

The performance of your PHP extensions can be improved by using efficient algorithms and data structures, minimizing memory usage, and optimizing your C++ code. Additionally, PHP-CPP provides some features that can help improve performance, such as direct access to PHP variables and functions.

Can I contribute to the PHP-CPP project?

Yes, the PHP-CPP project is open-source and welcomes contributions from the community. You can contribute by reporting bugs, suggesting new features, or submitting patches.

Where can I find more resources on PHP extension development with C++?

There are many resources available online for learning about PHP extension development with C++. These include tutorials, sample code, documentation, and forums. Additionally, the PHP-CPP website provides a wealth of information and resources on using the library.

Taylor RenTaylor Ren
View Author

Taylor is a freelance web and desktop application developer living in Suzhou in Eastern China. Started from Borland development tools series (C++Builder, Delphi), published a book on InterBase, certified as Borland Expert in 2003, he shifted to web development with typical LAMP configuration. Later he started working with jQuery, Symfony, Bootstrap, Dart, etc.

BrunoSCcppoopOOPHPphp extensionsphp-cpp
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week