Develop PHP extensions with C and PHP-CPP: Advanced Topics and Best Practices
Key Points
__toString
In this article, we will further dive into the development of the Complex library, add more member functions, and address some advanced topics in writing object-oriented PHP extensions using PHP-CPP:
__toString
Let's get started.
Preparation
The entire process of preparing the environment is explained in the first article.
Return this pointer in C
As mentioned in the second article, we use member functions to perform various mathematical operations on complex numbers. In this demonstration, we will implement four such functions: add, sub, mul, and div. I will explain the first three first. The div function involves exception handling, which will be discussed later.Let's take a look at the mul function (for multiplication). The add and sub functions are roughly the same.
Php::Value add(Php::Parameters ¶ms) { Php::Value t = params[0]; Complex *a = (Complex *) t.implementation(); r += (double) a->getReal(); i += (double) a->getImage(); return this; }
Returning this pointer from C to PHP is simple. Inside this C function, this pointer (as Complex* type) can be returned to PHP as Php::Value type. The conversion does not lose any object information. It also does not require explicit type conversion.
Return Complex object pointer
Returning this usually means that the object itself has changed. But in some cases we might want to return a new object and leave the "current" object (call object) unchanged.
In our Complex class, we have a function like this that returns the conjugate number of a given complex number (a bi becomes a-bi).
Php::Value add(Php::Parameters ¶ms) { Php::Value t = params[0]; Complex *a = (Complex *) t.implementation(); r += (double) a->getReal(); i += (double) a->getImage(); return this; }
The key point here is that we have to use Php::Object to explicitly convert our Complex* object to Php::Object, so when the object is later parsed by the PHP script, the class information is properly ensured and kept Its accessibility.
The first parameter of this function is the class type, in this case trComplex. I'm using this name because I've 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 this pointer, but it is still manageable as long as you read the documentation and find the correct part. For more usage examples, you may want to read this section in the official PHP-CPP documentation.
Open __toString magic method
In our class, there is a __toString
function that prints plural numbers in a more readable way, for example: 1 2i. In my previous post, this function is not exposed (or "registered" in PHP-CPP terminology), but it can still be called from inside PHP. However, in order for this function to be called on the Complex object after we apply some mathematical operations (e.g. "echo $a->add($b)->sub($c)"), we need to be compiled It is explicitly registered in the extension:
Php::Value conjugate() { Complex *t = new Complex(); t->r = r; t->i = -i; return Php::Object("tr\Complex", t); }
The issue we submitted in the PHP-CPP repository Issue #150 discusses in detail why we have to do this.
Chain member function call
One thing that must be implemented in this class is to be able to link member functions so that we can do the following calculation: $a->add($b)->sub($c). The result should still be able to call its member functions.
This is done by the above method, that is, returning this pointer to PHP. However, older PHP-CPP libraries have errors when dereferenced objects, and if the link method is called, a "segment fault" is created.
The issue was submitted (#151) and a commit containing the PHP-CPP source code patch was submitted. If you are using an older version of the PHP-CPP library to compile the PHP-CPP library and your own library, please update the PHP source code and recompile and reinstall the PHP-CPP library and your library.
As explained in the submission summary:
complex.method("__toString", &Complex::__toString);
I'm glad my own project work can help the libraries I use become better.
Exception throwing and handling in PHP
Two more functions in our Complex class may throw exceptions back to PHP for processing: div and phi. The former performs division operation, while the latter returns the angle of the complex number, as shown in its alternative representation, polar coordinate representation (r, θ).
If you pass a plural number as a parameter (or caller), but the part and imaginary parts are actually 0, both operations may fail. For these two operations, we need to perform exception handling. Remember that we are throwing exceptions in C code, and the PHP script will catch the exception and do the necessary processing:
Php::Value add(Php::Parameters ¶ms) { Php::Value t = params[0]; Complex *a = (Complex *) t.implementation(); r += (double) a->getReal(); i += (double) a->getImage(); return this; }
In PHP scripts, we catch this exception like this:
Php::Value conjugate() { Complex *t = new Complex(); t->r = r; t->i = -i; return Php::Object("tr\Complex", t); }
The above code snippet will display the following text line:
complex.method("__toString", &Complex::__toString);
It's very simple, right? The C exception constructed in our extension is passed back to PHP and is correctly caught. In addition, we can operate exceptions like we handle native PHP exceptions thrown by other PHP codes!
Test all functions
Finally, we can compile and install the complex.so extension for our PHP installation via make && sudo make install
. If all goes well, we can verify the installation of the extension by issuing the following command in the terminal:
<code>修复问题#151,链式方法调用无法正常工作…… ……因为每个对象的引用计数未正确更新,这导致即使对象已分配给不同的变量,该对象也会被销毁。</code>
The terminal should display a line that says "/etc/php5/cli/conf.d/complex.ini", we can make sure that our extension is installed and ready to be called by any PHP script.
Note: If we check 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 Apache can load it, we change the following line:
Php::Value div(Php::Parameters ¶ms) { Php::Value t = params[0]; Complex *b = (Complex*) t.implementation(); double t1 = b->mod() * b->mod(); if (t1 == 0) 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; }
The test PHP script for this extension is as follows, with some notes:
$a=new tr\Complex(1,2); $c=new tr\Complex(); //$c实际上是0+0i try { $res=$a->div($c); } catch(Exception $e) { echo "Caught exception: ".$e->getMessage()."\n"; } }
All test scripts should run correctly and the exception is caught correctly.
Conclusion
This summarizes my 3 article series on building this powerful library with C for PHP extensions. We cover the basics, object-oriented aspects, and some advanced topics in object-oriented programming. We also helped PHP-CPP improve.
What else can we do with PHP-CPP? I'll quote a few lines of email communication I received from Emiel Bruijntjes (co-author of PHP-CPP):
If you are working on a project and have one or more of the following requirements, the PHP-CPP library is ideal: – You are working on software/data structures/algorithms and you want to make sure that your software can also be used in non-PHP projects in the future. – You want to use a tool or library that is not yet available as a PHP extension. – You want better performance of your C/C code (compared to PHP), but you also want to build structured, object-oriented code for easy understanding and maintenance by other developers/colleagues.
The possibilities are huge: frameworks (such as Phalcon), template languages (such as Smarty or Twig), and so on.
Please leave your comments and opinions and let us know what you have done with this library!
FAQs on Developing PHP Extensions with C
There are many benefits to developing PHP extensions using C. First, it allows you to take advantage of the power and flexibility of C in your PHP application. This can improve performance, especially in compute-intensive tasks. Second, it provides a way to reuse existing C code in a PHP environment, which can save a lot of development time and effort. Finally, it enables you to create custom PHP extensions that extend the functionality of PHP and provide features that are not available in the standard PHP library.
To start using C for PHP extension development, you need to have a basic understanding of PHP and C programming languages. You also need to install the PHP development environment and the C compiler. After installing these prerequisites, you can start writing PHP extensions in C. There are a lot of resources available online, including tutorials and sample code to guide you through this process.
PHP-CPP is a library for developing PHP extensions using C. It provides a set of C classes and methods, simplifying the process of writing PHP extensions. With PHP-CPP, you can write PHP extensions in a more natural and intuitive way, using C's familiar syntax and concepts. This can make the development process more efficient and reduce errors.
Yes, PHP-CPP is open source software that can be used in personal and commercial projects. However, it is 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 maintain your PHP extensions.
Some common challenges in PHP extension development using C include the correct management of memory, handling of errors and exceptions, and the interface between PHP and C. These challenges can be overcome by gaining insight into PHP and C, using good programming practices, and leveraging the features and tools provided by PHP-CPP.
PHP extensions written in C can be debugged using standard C debugging tools. In addition, PHP-CPP provides some features that can aid debugging, such as exception handling and error reporting.
Yes, PHP-CPP can be used with other C libraries. This allows you to take advantage of various C features in PHP extensions.
You can improve the performance of PHP extensions by using efficient algorithms and data structures, minimizing memory usage, and optimizing C code. In addition, PHP-CPP provides some features that can help improve performance, such as direct access to PHP variables and functions.
Yes, the PHP-CPP project is open source and the contribution of the community is welcome. You can contribute your code by reporting bugs, suggesting new features, or submitting patches.
There are many resources available online for learning to use C for PHP extension development. These resources include tutorials, sample code, documentation, and forums. In addition, the PHP-CPP website provides a large amount of information and resources on the use of the library.
The above is the detailed content of Developing PHP Extensions with C and PHP-CPP: Advanced. For more information, please follow other related articles on the PHP Chinese website!