PHP7扩展开发教程[7] – 如何创建对象?

请确定你已阅读《PHP7扩展开发教程[6] – 如何调用PHP函数?》。

小憩一下

近些天连续的编写教程倍感疲惫,好在重要的内容已经讲过去大半,剩下的内容会陆陆续续写完。

在我的计划之中,整个教程应该在10篇左右,从本章开始的剩余的内容将会简单的多,希望可以尽快完成,呈现一个完整的教程给大家。

遥想从前,对于PHP扩展开发也是敬而远之的态度,主要是因为没有相关联的工作需求,后来是因为工作中需要真正用到扩展开发,所以才懵懵懂懂的走上了这条路。

虽然坎坎坷坷开发完了扩展,实际上对Zend API的认识仍旧非常模糊,以至于写出来的扩展只是”能用”而已。好在我本身对这个技术很有兴趣,同时也正是因为网上关于PHP扩展开发的博客少之又少,遇到问题几乎无法解决,只能求助源码,更别提PHP7已经大变样了。

正是如此,所以我决定从头学起,也就有了这篇教程。

正式开始

本章代码:https://github.com/owenliang/php7-extension-explore/tree/master/course7-how-to-create-object

我的目标是在一个全局函数中,调用类的静态方法,然后创建类对象并调用它的非静态方法,让我们开始吧。

首先,我为myext类增加了一个static方法叫做print_author,它将输出一段信息:

可以看一下这个方法的实现zim_myext_print_author,非常简单:

这里需要关注的是php_output_write函数,它相当于PHP里的echo方法,相关定义如下:

一般我们用第2个就可以,因为带缓存的输出性能会更好点。


接下来,我定义一个全局函数zif_myext_test_object,在导出扩展时注册它:

现在,我们具体来看一下这个全局函数的实现,代码将分段讲解。

首先,我创建了一个string类型的zval,其值是类名myext。将类名传给zend_lookup_class方法,可以返回对应类的class句柄。通过断言我可以确定,zend_lookup_class返回的class句柄,与我注册myext类得到的class句柄是同一个对象。最后释放myext_classname的内存,因为不再使用。

在这里我们完全可以直接使用注册myext类时返回的class句柄,然而如果该类不是我们自己注册的类,那么就只能通过zend_lookup_class去获得了。

有了class句柄,接下来我要调用myext的静态方法print_author,因此我开始准备zend_call_function的第1个调用参数:

与上一章相比,object设置为了NULL,因为我们调用的是静态方法并没有对象,其他字段并没有什么区别。

接下来,我在myext的句柄的function_table里找出print_author方法,它底层数据是一个zend_function,前一章我们已经见过了。

接下来,我们定义第2个参数,function_handler指向print_author方法。calling_scope代表被调用函数所属的class句柄,所以填myext_handle。called_scope表示当前所处的类,我们不在类内部,所以传NULL。最后的object填NULL就不必多说了。

现在调用zend_call_function可以成功调用到myext类的静态方法print_author,打印出一段话在屏幕上,断言确认了返回值是True类型。


现在,我们尝试创建一个myext对象:

这里主要用到了object_init_ex方法,它第1个参数是一个未经初始化的zval,第2个参数是要创建的类对应的class句柄。

我们也可以像PHP里new Object()一样,创建一个默认类型的对象,其方法名是object_init,相关定义如下:

在创建对象的时候,Zend并不会帮我们调用构造函数,需要我们自己显式的在object上调用__construct方法:

先创建函数名ctor_name,然后通过便捷函数call_user_function调用即可。

类似的,接下来调用一下obj的strtolower方法,整个过程我们已经很熟悉了:

先创建函数名func_name,再准备调用参数param以及返回值容器retval2,最后调用call_user_function完成调用。最后不要忘记释放资源,函数名,参数,返回值。

到这里还没有结束!如果你的object不再使用,也请释放它:

结语

本章你应该掌握:

  • 获取任意类的class句柄。
  • 调用类的静态方法。
  • 创建类对象。

下一章,我将展示如何定义全局常量,以及获取全局变量($_GET,$_POST)。

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~