经过两周的迭代,Deliverer目前更新到1.0.8https://github.com/zhoumengka...因为是为了解决祖传代码的问题,我也听过朋友们有些声音,支持PHP5还是很有必要的,所以这段时间一直在努力解决这个版本的兼容性问题,没想到问题比我想象的要难很多。把开发中遇到的问题(主要是体力活)记录下来,想分享给大家,有兴趣的朋友可以fork一份,让自己对代码不至于那么陌生,期待大家的PR。在PHP7中,函数或方法在执行时是在zend_execute_data结构体中的execute_data->call->fbc,而在PHP5中对应字段获取调用函数的函数,两者差距比较大。后来发现在PHP5的zend_execute_data的opline中找到了当前执行的函数信息,但是PHP5.4之前和之后的逻辑还是有区别的,需要区别对待(幸好是编译器的字段提示错误)#ifPHP_VERSION_ID<50400#defineOP1_FUNCTION_PTR(n)(&(n)->op1.u.constant)#else#defineOP1_FUNCTION_PTR(n)((n)->op1.zv)#endif初始call解决了,发现embeddedcall已经不在opline中了。而且版本不一样,获取的地方也不一样,版本号也和上面opline判断的版本号不一样,只能靠体力来衡量了。#ifPHP_VERSION_ID<50500if(execute_data->fbc!=NULL){fbc=execute_data->fbc;}#elseif(execute_data->call!=NULL&&execute_data->call->fbc!=NULL){fbc=execute_data->call->fbc;}#endif最终得到的函数信息是多层判断zend_function*fbc;#ifPHP_VERSION_ID<70000#ifPHP_VERSION_ID<50500if(execute_data->fbc!=NULL){fbc=execute_data->fbc;}#elseif(execute_data->call!=NULL&&execute_data->call->fbc!=NULL){fbc=execute_data->call->fbc;}#endifif(fbc==NULL){fbc=get_function_from_opline(execute_data->opline);}#elseif(execute_data->call!=NULL&&execute_data->call->func!=NULL){fbc=execute_data->call->fbc;}#endifqueryfromopline得到的只是函数名,需要在全局函数表中找到对应的函数指针staticzend_function*get_function_from_opline(zend_op*opline){zend_function在*fbc上;zval*function_name=OP1_FUNCTION_PTR(opline);如果(Z_STRVAL_P(function_name)==NULL){返回NULL;}if(zend_hash_find(EG(function_table),Z_STRVAL_P(function_name),Z_STRLEN_P(function,_name)+1void**)&fbc)==FAILURE){returnNULL;}returnfbc;}总体来说PHP5的处理要比PHP7复杂很多,这也说明PHP7做的更好。像这些都是这几天的开发工作,可能还有很多实际的线上环境你没有遇到过。如果大家有兴趣,可以使用这个工具来解决问题,也可以一起来完善这个小工具。下周或者下周我会添加watch功能,支持函数和方法的参数打印。主要是对比Java的Arthas,因为trace和watch功能是我最常用的。虽然PHP可以直接在线修改添加日志,但是这毕竟不规范,发布过程也太慢了。我觉得这个手表功能还是很有用的。必要的,大概$./bin/deliverer-wfoo-n3的意思是监听foo函数调用3次后退出,打印出deliverer-request-id及其入参,可以根据deliverer-查看request-id完整调用堆栈。对此感兴趣的请给个star,https://github.com/zhoumengka...安装使用有问题欢迎加我微信zhoumengkang进行骚扰,密码:deliverer
