Timber\PostType::__toString()返回字符串报错无堆栈追踪排查咨询
问题解答
触发Timber\PostType::__toString()的常见场景
PHP 中的__toString()是魔术方法,会在对象被当作字符串处理时自动触发,结合你使用的Timber+Twig技术栈,常见触发场景如下:
- Twig模板中直接输出
PostType类型的变量,例如{{ post.type }}这类写法,Twig渲染时会自动调用__toString()转成字符串输出,你报错的栈顶在Twig的eval执行代码,说明90%以上的概率是模板渲染时触发的 - PHP代码中直接将
PostType对象和字符串拼接,例如$type_str = '当前文章类型:' . $post_type_obj - 调用字符串处理函数时直接传入
PostType对象,例如str_contains($post_type_obj, 'product') - 调用WordPress核心方法时,需要传入文章类型字符串的参数位传入了
PostType对象,例如get_posts( [ 'post_type' => $post_type_obj ] )
堆栈追踪生成与排查方案
因为__toString方法在PHP 7.4之前版本不允许直接抛出异常(否则会直接触发致命错误),所以我们可以直接修改__toString方法加入调试日志逻辑,替换原有方法代码即可:
public function __toString() { // 校验slug类型是否合法 if (!is_string($this->slug)) { // 生成调用堆栈,忽略参数减少日志体积 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $log_content = date('Y-m-d H:i:s') . " PostType __toString错误触发堆栈:\n"; foreach ($trace as $index => $item) { $log_content .= sprintf( "#%d %s(%d): %s%s%s\n", $index, isset($item['file']) ? $item['file'] : '未知文件', isset($item['line']) ? $item['line'] : 0, isset($item['class']) ? $item['class'] : '', isset($item['type']) ? $item['type'] : '', $item['function'] ); } // 日志路径替换为你服务器上可写的日志路径,不要和站点原有error_log重名避免冲突 file_put_contents('/var/www/debug/timber_posttype.log', $log_content . "---\n", FILE_APPEND); // 兜底返回字符串,避免触发 recoverable fatal error return is_null($this->slug) ? '' : (string)$this->slug; } return $this->slug; }
补充排查建议
- 优先检查
init($post_type)方法的逻辑,是否存在修改$this->slug为非字符串类型的代码(比如赋值为null、数组、对象),这是你当前问题的最高发原因:构造函数中你虽然传入了字符串类型的$post_type,但后续init方法执行时可能修改了该属性 - 可以将构造函数的参数加上强类型声明
public function __construct(string $post_type),如果传入的参数本身不是字符串,会直接抛出参数类型错误,比__toString报错更容易定位 - 临时开启PHP的xdebug扩展也会自动在error_log中追加所有错误的完整堆栈,生产环境排查完成后请及时关闭xdebug避免性能损耗
内容的提问来源于stack exchange,提问作者EBennett
相关产品推荐
相关产品推荐

