set_error_handler在frankenphp worker模式中仅作用于单个worker进程生命周期,随进程启动而生效、退出而失效,需在入口文件顶层显式注册,无法捕获fatal error。

Worker模式下set_error_handler的作用范围是单个Worker生命周期
在FrankenPHP Worker模式中,set_error_handler注册的函数**只对当前Worker进程内发生的错误生效**,不是全局、也不是跨请求持久有效——它随Worker启动而生效,随Worker退出(如被主进程重启、OOM终止或主动调用exit())而失效。
这意味着:一个Worker常驻内存期间处理的全部HTTP请求、WebSocket帧、定时任务回调,只要发生在该Worker进程上下文中,其E_WARNING/E_NOTICE等错误都会被这个handler捕获;但一旦Worker重启,就必须在新进程里重新调用set_error_handler,否则后续请求的错误将回退到PHP默认行为(输出到error_log或空白页)。
- Worker启动时必须显式注册,不能依赖“一次设置、永久生效”
- 若Worker中使用了
pcntl_fork或手动fork(),子进程不会继承父进程的error handler,需各自注册 - 在
frankenphp_handle_request循环外注册(如Worker入口文件顶部)是安全且推荐的做法 - 注意不要在每次请求处理函数里重复调用
set_error_handler,可能覆盖前一次注册,且无必要
为什么worker\_connections这类Nginx参数和它无关
worker_connections是Nginx的配置项,而FrankenPHP Worker模式**完全不经过Nginx**——它自己监听端口、解析HTTP、调度PHP执行。所以你在FrankenPHP里根本看不到、也无需配置worker_connections。混淆这点容易导致监控错位或调优方向错误。
FrankenPHP自身的并发能力由两个指标决定:frankenphp_total_threads(线程总数)和frankenphp_busy_threads(当前忙线程数)。前者在Caddyfile里通过php指令的max_workers或环境变量FRANKENPHP_MAX_WORKERS控制;后者反映实时负载,可用于自动扩缩容判断。
- 想限制并发请求数?调
max_workers,不是去改Nginx配置 - 看到
frankenphp_busy_threads持续接近frankenphp_total_threads?说明线程池已饱和,需扩容或优化单请求耗时 - 错误日志暴增但
frankenphp_busy_threads很低?大概率是Worker内部逻辑异常(如死循环、阻塞I/O),而非并发压力问题
set_error_handler在Worker中抓不到Fatal Error
set_error_handler对Fatal Error(如ParseError、Fatal error: Allowed memory size exhausted)完全无效——这是PHP底层引擎级中断,连register_shutdown_function都只能做“事后收尸”,无法阻止进程退出。
Worker模式下这尤其关键:一个未捕获的Fatal Error会导致整个Worker进程崩溃,触发FrankenPHP主进程拉起新Worker。如果高频发生,就会看到frankenphp_total_threads频繁波动、frankenphp_queue_depth持续堆积。
- 务必配合
register_shutdown_function记录致命错误上下文(error_get_last()) - 在Worker启动阶段用
ini_set('memory_limit', ...)设合理上限,避免OOM直接kill - 用
frankenphp_get_metrics_registry()暴露自定义指标,比如frankenphp_worker_crashes_total{worker="chat"},便于告警 - 不要指望
set_error_handler兜底所有问题,Fatal Error必须靠代码健壮性和资源约束来预防
实际部署时最容易忽略的初始化时机
很多人把set_error_handler写在路由处理函数里,结果发现只对第一个请求生效,后续请求错误没被捕获——因为FrankenPHP的Worker是复用的,但路由函数每次请求都重新执行,导致handler被反复覆盖或漏注册。
正确做法是在Worker的**顶层作用域**(即worker.php或入口文件最外层)一次性注册,并确保它在frankenphp_handle_request循环之前执行。
- 错误写法:
function handle() { set_error_handler(...); ... }→ 每次调用都重设,且可能被覆盖 - 正确写法:文件开头就
set_error_handler($myHandler);,然后while (frankenphp_handle_request(...)) {...} - 如果用了Composer自动加载,确保
vendor/autoload.php也在注册handler之前引入 - 测试是否生效:故意触发一个
E_USER_WARNING,看是否进入你的handler而不是默认输出
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











