PHP调试总卡壳?老工程师的3个断点盲区
|
上周三下午,线上订单支付页突然卡在 loading 三秒不动——没报错,没重定向,就是 PHP 处理完跳转前那半拍断掉了。我加了 Xdebug 断点,第一处在 controller 入口,停住了;第二处在 service 层逻辑开头,也停住了;第三处塞进 model 的 find() 里头……它根本没进去。 我原以为是 opcache 没刷干净,清了两遍缓存、重启 php-fpm、连容器都重跑了——没用。老张端着茶杯路过,瞥了一眼说:“你断点打在 PDO::prepare() 里试试?” 我照打了,还是没停。他摆摆手走了,嘴里嘟囔着“早说了别信 IDE 自动补的断点行号”。
文章配图,仅供参考 其实那天上午我就改过一行:把原本写死的 MySQL 主机地址换成了环境变量 $_ENV['DB_HOST'],但忘了 check 这个值是否真被加载进来——它在 .env 里,在 docker-compose.yml 里也在,可 phpinfo() 里没它。我后来 grep 了整个项目目录,发现 config/database.php 里有段注释掉的代码:// putenv("DB_HOST=127.0.0.1") ——它没生效,但也没报错。反正 PHP 就是默默把 $_ENV['DB_HOST'] 当 null 用了,PDO 构造时传了个空字符串当 host,结果呢?connect timeout 是三十秒,但 Xdebug 在这之前根本不触发——因为 connect 阶段压根没走到断点那行。它卡在 mysqli_real_connect() 底层,静默等超时,而 IDE 显示“断点未命中”,我以为是断点失效。对了,办公室空调修了三次,第二次修完出风口歪了,风一直往我后脖颈吹。还有,隔壁工位小刘昨天交了辞职信,说要去考烘焙师——我也不知道真假,他桌上那本《法式甜点化学》摊开着,页角卷得厉害。 我换了种方式,把断点设在 PDO 构造函数的 __construct() 第一行,这次进了。然后发现 $dsn 字符串里 host 部分是空的;再往上翻,果然 $_ENV['DB_HOST'] 是 null。不是 getenv() 被禁用,也不是 .env 没加载——是我们自己写的 env 加载器有个判断:if (empty($_SERVER['APP_ENV'])) 就不加载 $_ENV,而 docker 里 APP_ENV 是小写 app_env,strcasecmp 比较没做……我们比的是 ===。我改回来,重新 reload,页面一下就跳走了。 但问题不在这儿。问题是我花了二十来分钟才意识到:Xdebug 的断点,只在 PHP 用户态代码里有效;一旦调用进扩展 C 层(比如 mysqli_real_connect),哪怕你在扩展源码里写了 debug 语句,Xdebug 也看不见——它不会拦,不会报,不会标灰,就让你觉得“断点丢了”。这个盲区我踩过第八次。可它不报错啊,就卡着,浏览器 spinner 转,服务器日志空着,连 slowlog 都没记录——因为根本没进 slowlog 触发阈值,它还没开始执行,只是悬在那儿。 所以说 PHP 调试总卡壳?优胜劣汰罢了。活下来的不是最懂 Xdebug 的人,是那些见过八次 connect 卡住、却还在查 controller 日志的人。上次那个新人,盯着 Laravel 的 DB::connection()->getPdo() 报错堆栈看了四十分钟,其实 PDO 对象根本没建出来——报错那行,是他加的 echo,根本没执行到。而我今天下午两点零七分,在 vendor 目录里手动加了一句 trigger_error('here'),它终于响了,响得特别突兀,像一声咳嗽。 对了,咖啡机又坏了,今天第三杯倒出来是温的。还有,行政说新工牌下周发,旧卡刷门禁有时灵有时不灵,中午我被拦在茶水间外两分钟——门禁系统用的也是 PHP 写的 API,没人敢动。 所以你看,断点没进、没报错、没日志、甚至没超时提示……但它就是不动。你对着 Xdebug 面板看三分钟,它蓝灰色的圆点安安静静,像在嘲笑你。我也不知道为什么必须把断点设在 new PDO() 里才能捕获这个 null host,而不是设在更下游的 query 方法里——按理说,它该在 prepare 时才崩才对。但现实是,它先崩在连接上,然后就不崩了,只是卡着。 有谁碰到过这个吗? (编辑:航空爱好网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


WHOOPS PHP调试库的使用

