工程师手记-升级PNI以支持PHP7

本文内容简介

  • 简要介绍本博客写作背景和目的:升级PHP Native Interface的代码使其支持PHP7。
  • PNI 升级以支持PHP7的过程做简单介绍。
  • 对这次升级的思路和方法进行总结。
  • 思维发散,假设其他情况下应该用什么样的方法进行升级php7的扩展。

背景和目的

PNI在2016年10月之前仅支持php5系列的版本。9月份时进行升级,使其支持PHP7。

PNI是什么? 具体参考这边博文《PHP Native Interface》。PNI代码规模只有1000行左右,升级大概花费了一周时间(工作外时间),其中包含2天寻找思路、2天的代码升级,3-4天的问题排查。

这篇博客记录了一下PNI升级过程,包括自己学习PHP7扩展框架、API定义的过程,调试、压测、修复bug的过程等。

把这些东西记录下来,主要是为了总结出自己的学习方法和操作方法。写成博客后,可以更好地帮助自己反思升级过程中是否有哪些不好的地方。当然其中也会有自己的成功经验。

PNI 升级过程简述

面临哪些问题,以及有哪些不确定的地方?

  • 代码从何处改起?
  • 如何保证编译通过?
  • 功能能否保证不变,以及PNI自身定义的PHP接口是否需要发生变化。
  • 升级过程中遇到bug和陷阱怎么办?
  • 这次升级的代价有多大?

升级PNI,从哪入手?寻找突破点的过程。

用搜索引擎搜到了几篇博客,都是介绍PHP7和PHP5的 zend api 不同的网文。随意浏览了一下,感觉帮助不是特别大。

自己下载了PHP7.0的源代码,编译一下,稍微看了一下 Zend的源码(主要看Zend_API、zend_list、zend_hash),少数几个ext里的扩展的源码。

看了后收获特别大, 了解了 php7扩展编写的几个特点:

  • php7 ext 扩展编写框架结构变化小
  • API函数名称变化小,多数无变化
  • API函数参数列表变化大
  • 宏的变化小

升级的思路就有了。

升级方法?

依据发现的php7扩展代码的特点,决定以PHP5版本的PNI的代码为基础,进行升级。代码不需要做太大的变动,更不需要完全重写。

设立3个目标,并按顺序分步骤实现。 1. 升级代码,编译通过。 2. 功能验证通过。 3稳定性验证通过。

为了达到第一个目标,使编译通过,使用下面方法:

  • 参考其他extention,首先对比php7和php5扩展的框架,优先修改PNI的框架。

  • 对比PHP7 源码中的zend_API.h、zend_list.h、zend_hash.h等。

  • 要修改的函数多,可能会有API没有升级被遗忘怎么办? 所以一边升级代码,一边make,看着gcc的错误提示去一点一点改正代码。

达到第2个目标的方法,则多写功能验证的测试case。

达到第3个目标的方法,是做压力测试,观察内存和cpu的使用情况。

  • 观察变量和资源是否被及时回收,是否有内存泄漏
  • 观察cpu负荷是否过高

在升级过程中遇到过最大的一个问题是,pni中遇到了内存泄漏。为了定位内存泄漏的原因,花了非常多的时间。

  • 打日志,定位内存泄漏逻辑。
  • 定位后,添加efree、free等函数调试。
  • 添加efree逻辑无效,打印对象引用计数的个数
  • 找到原因,是存储资源类型的变量,作为另一个对象的属性时,如果对象释放,存储资源类型的成员变量不会主动释放。
  • 解决办法,在对象释放的析构函数中,添加释放资源的逻辑。

总结

总体上说,这次升级PNI比较顺利。

在做的过程中,思路其实并没有上面写的那么清楚,心中也只有个大概思路。

在刚开始时,寻找从何下手的过程中,还是走了一点弯路,但浪费的时间不多。

走的最大的弯路则是,上文说的定位和解决pni内存泄漏的过程中, 没有首先想到去观察对象或变量的引用计数的。这使pni升级的过程直接阻塞了。今后遇到内存泄漏的情况,应该首先观察zval的引用计数数目是否为0.

思维发散

下面开始做各种假设,假设我会面临不同的情况(实际并不存在),我该设计什么样的思路和方法进行PNI的升级呢?

  • 假设PHP7和PHP5扩展开发的框架和结构有大的不同,对PNI的升级,完全重写也许是好方案。

  • PNI的代码规模只有1000行,假设10W行规模以上,我在达到上文说的,第1个编译通过的目标,就不能直接用gcc的错误信息去定位没有升级的代码,不能用一边改代码一边查php7 zend api代码。应该把PHP7的代码都给熟悉了,再去升级代码。

  • 假设升级代码规模大,php7的扩展框架和代码与php5也有大不同呢?学习成本和工程量将变得非常大,这种情况怎么做呢? 1.大规模的代码,逻辑上应该做好分层和抽象。 在升级大规模代码前,应该先写一个小的PHP7扩展,拿来练手,这样学习的曲线就会平缓很多。

工程师手记-升级PNI以支持PHP7》上有7条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax