引言
在前一篇文章《Windows下编写php扩展(三)利用php-cpp在window上快速开发PHP扩展》说明了使用php-cpp开发php扩展的过程。
已移植到windows的phpcpp项目的完整的vs2017解决方案可在此 下载
接下来谈一谈在用php-cpp开发php扩展的时候,如何进行调试。在php脚本中调用扩展,有一点非常值得关注,那就是如何将php中的变量做为参数传入到扩展中函数,实际传入的内容到底是什么,是什么样的数据结构等等。
本次的实验环境和上一篇文章中用到的一样,还是win10 企业版,visual C++ 2017 社区版。
调试dll的一般过程
对dll进行调试与对可执行程序进行调试有一点不同,调试可执行程序时不用专门指定启动程序,但是由于dll不能直接运行,因此要指定一个调用dll的可执行程序做为启动程序。在本文中要进行php扩展的调试,当然可执行程序就是 php.exe。
还要注意到一点,php.exe 调用php脚本,在php脚本中调用 php扩展。所以在启动程序中指定命令行参数,需要指定这个要执行的脚本文件。
因为要进行调试,所以要在项目中生成调试信息文件 *.pdb。
调试php扩展的实际过程
在前一篇文章中已经介绍了使用phpcpp开发php扩展的基本过程,项目的基本结构如下图所示:项目的源码可在此处下载
为了项目可以进行调试,还要对项目进行一些设置。
由于以前只是设置了release模式,现在还需要添加一个Debug模式
选择 项目属性/配置管理器
然后 新建 一个配置项 Debug
针对这一个Debug-x64配置项进行如下行设置
在“调试”选项卡中设置3项
(1) 命令: php.exe的完整路径名称 ,备注,这里设置的是php7.2.4版的可执行文件php.exe的路径名
(2) 命令参数 : test.php
(3)工作目录: php.exe所在的目录
其中test.php是调用了扩展函数的php脚本,其内容如下
<?php
$x = array();
$x[] = ['abc',13];
$x[] = ['def',3];
my_test($x);
这个脚本比较简单,定义了一个数组,以数组做为参数调用扩展项目中的函数 my_test。
接下来做如下设置,注意红色标记出来的内容
下面是php扩展项目中的main.cpp的内容,在其中实现了一个扩展函数 my_test
#include "phpcpp.h"
void my_test(Php::Parameters ¶ms)
{
// there is one input array, cast the PHP variable to a vector
std::vector<Php::Value> input = params[0];
// loop through the array
for (size_t i = 0; i < input.size(); i++)
{
std::vector<Php::Value> v = input[i];
Php::Value t = v[0];
const char * s = t.rawValue();
Php::out << v[0] << v[1];
}
}
/**
* tell the compiler that the get_module is a pure C function
*/
extern "C" {
__declspec(dllexport) void *get_module()
{
// static(!) Php::Extension object that should stay in memory
// for the entire duration of the process (that's why it's static)
static Php::Extension extension("myPhpcppExt1", "1.0");
extension.add<my_test>("my_test", { Php::ByVal("input", Php::Type::Array) });
// return the extension
return extension;
}
}
为了以后叙述的方便,将php.exe所在的目录称为 {phpExe},将php扩展项目所在的目录称为{phpExtPrj}
现在生成解决方案, {phpExtPrj}\x64\Debug 目录下的内容应该如下图所示
将其中的 myPhpcppExt.dll 复制到 {phpExe}\ext\myPhpcppExt.dll。这一步不仅是针对调试,在前一篇文章中说过,要想使用myPhpcppExt.dll,就得将该dll复制到 {phpExe}\ext,并修改php.ini ,添加加载指令,只不过在调试模式下生成的dll与原来单纯运行的dll相对,内容发生了变化,所以还得再复制一遍。
补充:前一篇文章中提到的phpcpp.dll应放在{phpExe} 目录,上文提到的test.php也应放在{phpExe} 目录。
接下来在扩展项目的源文件中设置断点,便于观察从php脚本中传入的变量的内容
单击工具栏上的开始调试按钮(或F5),就会发现程序在上图所示的断点处中断
请留意上图红色箭头指出的字符串的值 “abc”,
<?php
$x = array();
$x[] = ['abc',13];
$x[] = ['def',3];
my_test($x);
正是测试脚本test.php中第3行所设置的数组$x的第一个元素的数组项中的第1个元素’abc’。
实验进行到这里,其它的调试工作就与普通的可执行程序的调试工作没有什么特别不同的地方了。感兴趣的朋友可以自已动手试一试。