使用C 和PHP-CPP开发PHP扩展:高级主题和最佳实践
关键要点
__toString
魔术方法、链接成员函数调用以及PHP中的异常抛出和处理。在我之前的文章中,我介绍了使用C (第一篇文章和第二篇文章)创建PHP扩展的PHP-CPP库。在后一篇文章中,我演示了使用Complex类进行复数运算的编写PHP扩展的面向对象方面。
该介绍并不完整,因为该文章的主要重点更多地放在演示PHP-CPP的面向对象能力上,而不是面向对象的实现细节上。
在本文中,我们将进一步深入研究Complex库的开发,添加更多成员函数,并解决使用PHP-CPP编写具有面向对象功能的PHP扩展中的一些高级主题:
__toString
魔术方法;完整的Complex库源代码以及测试PHP脚本位于此Github存储库中。
让我们开始吧。
准备工作
在第一篇文章中解释了准备环境的整个过程。
在C 中返回this指针
如第二篇文章所述,我们使用成员函数对复数执行各种数学运算。在此演示中,我们将实现四个这样的函数:add、sub、mul和div。我将首先解释前三个。div函数涉及异常处理,稍后将讨论。
让我们看一下mul函数(用于乘法)。add和sub函数大致相同。
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; }
注意:在本文中,我将不介绍一些之前讨论过的基本主题,例如修改Makefile和ini文件、注册成员函数、类和命名空间等。请参考前面的部分了解这些内容。
将this指针从C 返回到PHP很简单。在这个C 函数内部,this指针(作为Complex *类型)可以作为Php::Value类型返回到PHP。转换不会丢失任何对象信息。它也不需要显式类型转换。
返回Complex对象指针
返回this通常意味着对象本身已更改。但在某些情况下,我们可能希望返回一个新对象并保持“当前”对象(调用对象)不变。
在我们的Complex类中,我们有一个这样的函数,它返回给定复数的共轭数(a bi变为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; }
这里的关键点是,我们必须使用Php::Object将我们的Complex *对象显式转换为Php::Object,因此当该对象稍后由PHP脚本解析时,可以正确保留类信息并保持其可访问性。
此函数的第一个参数是类类型,在本例中为trComplex。我使用此名称是因为我已将此类(“Complex”)包装到单独的命名空间(“tr”)中。
第二个参数是要传回的对象。
返回新的类实例比只返回this指针要棘手一些,但只要您阅读了文档并找到了正确的部分,仍然是可以管理的。有关更多用法示例,您可能需要阅读PHP-CPP官方文档中的这一部分。
公开__toString魔术方法
在我们的类中,有一个__toString
函数,它以更易读的方式打印复数,例如:1 2i。在我之前的文章中,此函数未公开(或在PHP-CPP术语中“注册”),但仍然可以从PHP内部调用。但是,为了使此函数在我们应用一些数学运算(例如“echo $a->add($b)->sub($c)”)后能够在Complex对象上调用,我们需要在已编译的扩展中显式注册它:
Php::Value conjugate() { Complex *t = new Complex(); t->r = r; t->i = -i; return Php::Object("tr\Complex", t); }
我们在PHP-CPP存储库中提交的问题Issue #150详细讨论了我们必须这样做的原因。
链式成员函数调用
必须在此类中实现的一件事是能够链接成员函数,以便我们可以进行如下计算:$a->add($b)->sub($c)。结果仍然应该能够调用其成员函数。
这是通过上述方法完成的,即返回this指针到PHP。但是,较旧的PHP-CPP库在取消引用对象时存在错误,如果链接方法调用,则会创建“段错误”。
已提交问题(#151),并提交了包含PHP-CPP源代码补丁的提交。如果您使用的是旧版本的PHP-CPP库来编译PHP-CPP库和您自己的库,请更新PHP源代码并重新编译和重新安装PHP-CPP库和您的库。
如提交摘要所解释:
complex.method("__toString", &Complex::__toString);
我很高兴我自己的项目工作可以帮助我使用的库变得更好。
异常抛出和PHP中的处理
我们的Complex类中还有两个函数可能会将异常抛回PHP进行处理:div和phi。前者执行除法运算,后者返回复数的角度,如其替代表示形式极坐标表示法(r,θ)所示。
如果将复数作为参数(或调用者)传递,但其实部和虚部为0,则这两个操作都可能失败。对于这两个操作,我们需要进行异常处理。请记住,我们要在C 代码中抛出异常,而PHP脚本将捕获异常并进行必要的处理:
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; }
在PHP脚本中,我们像这样捕获此异常:
Php::Value conjugate() { Complex *t = new Complex(); t->r = r; t->i = -i; return Php::Object("tr\Complex", t); }
上面的代码段将显示如下文本行:
complex.method("__toString", &Complex::__toString);
很简单,对吧?在我们的扩展中构造的C 异常被传回PHP并被正确捕获。此外,我们可以像处理其他PHP代码抛出的原生PHP异常一样操作异常!
测试所有函数
最后,我们可以通过make && sudo make install
为我们的PHP安装编译和安装complex.so扩展。如果一切顺利,我们可以通过在终端中发出以下命令来验证扩展的安装:
<code>修复问题#151,链式方法调用无法正常工作…… ……因为每个对象的引用计数未正确更新,这导致即使对象已分配给不同的变量,该对象也会被销毁。</code>
终端应该显示一行显示“/etc/php5/cli/conf.d/complex.ini”,我们可以确定我们的扩展已安装并准备由任何PHP脚本调用。
注意:如果我们检查此扩展的Makefile,我们将看到我们正在将此PHP扩展安装到其CLI环境中。如果我们想安装此扩展以便Apache加载它,我们更改以下行:
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; }
此扩展的测试PHP脚本如下所示,并带有一些注释:
$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"; } }
所有测试脚本都应该正确运行,并且异常被正确捕获。
结论
这总结了我关于使用C 构建PHP扩展的这个强大库的3篇文章系列。我们介绍了基础知识、面向对象方面以及面向对象编程中的一些高级主题。我们还帮助PHP-CPP有所改进。
我们还能用PHP-CPP做什么?我将引用几行我从Emiel Bruijntjes(PHP-CPP的合著者)收到的电子邮件通信:
如果您正在从事一个项目,并且具有以下一个或多个要求,则PHP-CPP库是理想的选择: – 您正在处理软件/数据结构/算法,并且您希望确保将来您的软件也可以用于非PHP项目。 – 您想使用尚未作为PHP扩展提供的工具或库。 – 您希望获得C/C 代码的更好性能(与PHP相比),但您还想构建结构化、面向对象的代码,以便其他开发人员/同事易于理解和维护。
可能性是巨大的:框架(如Phalcon)、模板语言(如Smarty或Twig)等等。
请留下您的评论和观点,让我们知道您使用此库做了什么!
使用C 开发PHP扩展的常见问题解答
使用C 开发PHP扩展具有多种好处。首先,它允许您在PHP应用程序中利用C 的强大功能和灵活性。这可以提高性能,尤其是在计算密集型任务中。其次,它提供了一种在PHP环境中重用现有C 代码的方法,这可以节省大量的开发时间和精力。最后,它使您能够创建自定义PHP扩展,这些扩展可以扩展PHP的功能并提供标准PHP库中不可用的功能。
要开始使用C 进行PHP扩展开发,您需要对PHP和C 编程语言都有基本的了解。您还需要安装PHP开发环境和C 编译器。安装这些先决条件后,您可以开始用C 编写PHP扩展。网上有很多资源可用,包括教程和示例代码,可以指导您完成此过程。
PHP-CPP是一个用于使用C 开发PHP扩展的库。它提供了一组C 类和方法,简化了编写PHP扩展的过程。使用PHP-CPP,您可以以更自然和直观的方式编写PHP扩展,使用C 熟悉的语法和概念。这可以使开发过程更高效,并且减少错误。
是的,PHP-CPP是开源软件,可用于个人和商业项目。但是,重要的是要理解,虽然库本身是免费的,但您可能需要投入时间和资源来学习如何有效地使用它以及维护您的PHP扩展。
使用C 进行PHP扩展开发的一些常见挑战包括正确管理内存、处理错误和异常以及PHP和C 之间的接口。可以通过深入了解PHP和C 、使用良好的编程实践以及利用PHP-CPP提供的功能和工具来克服这些挑战。
可以使用标准C 调试工具调试用C 编写的PHP扩展。此外,PHP-CPP提供了一些可以帮助调试的功能,例如异常处理和错误报告。
是的,PHP-CPP可以与其他C 库一起使用。这使您可以利用PHP扩展中的各种C 功能。
您可以通过使用高效的算法和数据结构、最大限度地减少内存使用以及优化C 代码来提高PHP扩展的性能。此外,PHP-CPP提供了一些可以帮助提高性能的功能,例如直接访问PHP变量和函数。
是的,PHP-CPP项目是开源的,欢迎社区的贡献。您可以通过报告错误、建议新功能或提交补丁来贡献代码。
网上有很多资源可用于学习使用C 进行PHP扩展开发。这些资源包括教程、示例代码、文档和论坛。此外,PHP-CPP网站提供了大量关于使用该库的信息和资源。
以上是使用C和PHP-CPP开发PHP扩展:高级的详细内容。更多信息请关注PHP中文网其他相关文章!