首先安装 xdebug, 无论是 OSX 上直接跑 fpm, 还是用虚拟机或 docker 都可以, 安装后, 配置 xdebug
[xdebug]
zend_extension=xdebug.so
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_connect_back=0
xdebug.remote_host=0.0.0.0
xdebug.remote_port=9001
xdebug.idekey=PHPSTORM
xdebug.remote_autostart=0
xdebug.profiler_enable=0
xdebug.profiler_enable_trigger=1
xdebug.profiler_enable_trigger_value=1111111
xdebug.profiler_output_dir=/path/to/profiling/folder
其中
remote_host在 mac 版的 docker 中, 需要配置为host.docker.internal才能在容器中访问到宿主机上的 PHPSTORM 进行断点调试.
其中关于性能报告的几项配置:
profiler_enable 为 0 关闭自动生成性能报告profiler_enable_trigger 为 1 开启触发生成性能报告profiler_enable_trigger_value 触发性能报告的 “密钥”profiler_output_dir 性能报告文件目录为了不过多影响本地调试, 关闭自动生成性能报告, 改由触发生成. 触发方式为在 GET / POST / COOKIE 变量中传一个 XDEBUG_PROFILE=${TRIGGER_VALUE}.
如果用 chrome 的话, 则可以安装 Xdebug Helper. 配置 trigger_value.

如果是用 postman 或是 insomnia, 则可以在 queryString 或是 requestBody, 甚至是 cookie 中传递.
在 mac 上使用的工具是 qcachegrind. 安装方式:
$ brew install graphviz
$ brew install qcachegrind
其中可能是我使用的系统版本比较新, 只有通过终端启动 qcachegrind 才能正常查看调用图.
根据 fpm 跑在宿主机还是虚拟机, xdebug 生成的性能报告中文件目录就会不一样. 首先是 fpm 跑在宿主机的情况.
命令行打开执行
$ cd /path/to/profiling/folder
$ qcachegrind
然后打开已经生成的报告文件

然后就可以了. 其中主要看调用次数, 时间消耗 (目前好像没有 xhprof 有的内存使用报告), 这里摘抄一下 xhprof 的几项关键信息, 同样适用于 xdebug.
funciton name : 函数名
calls: 调用次数
Incl. Wall Time (microsec): 函数运行时间(包括子函数)
IWall%:函数运行时间(包括子函数)占比
Excl. Wall Time (microsec):函数运行时间(不包括子函数)
EWall%:函数运行时间(不包括子函数)
我用 laravel 跑了一个简单的例子, 看这个图左边圈中部分, 有两项自身运行时间都超过 30% (Excl. Wall Time / Self). 右上圈中的是源文件中具体某一行的运行时间. 右下圈中的是执行次数.

个人习惯是打开性能报告后, 按照以下步骤定位性能问题:
Self 直接定位到具体问题就最好.Self 的时间不明显, 可以先看 controller 的运行时间, 如果占的百分比较大, 就可以通过 Source Code 中看其中每一行的运行时间如果是 php5.6 的项目, 还可以借助 xhprof 来查看内存使用情况.
如果 fpm 是跑在容器或是虚拟机中, 且站点目录跟宿主机不一致的话, 生成的报告就无法直接查看 Source Code, 那么可以配置目录映射 (用 phpstorm 的话肯定熟悉这个).

关于 qcachegrind 的安装和使用, 也可以参考下面的博文.