选择ThinkPHP不同版本如何影响PHP性能?配置优化方案有哪些?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1101个文字,预计阅读时间需要5分钟。
TP6是稳定版主分支,TP8(即ThinkPHP 8.0)是2024年初发布的全新架构,底层彻底切换为Swoole协程+支持异步,默认不兼容传统FPM模式。性能提升显著,在集中共享在高峰并发I/O场景,如大量Redis查询、HTTP微服务调用等;但对比纯模板渲染或简单CRUD,TP8因协程调度开销慢于TP6。
常见错误现象:Call to undefined function think\facade\Db() —— 这是 TP8 中废弃了全局门面,必须改用 think\db\Connection 或注入方式获取实例。
- TP6 默认运行在 PHP-FPM 下,兼容所有主机环境;TP8 要求 Swoole ≥ 5.1 且必须启用
enable_coroutine=1 - TP8 的
config('database')返回的是协程安全的连接池配置,不是原始数组,直接var_dump看不到实际参数 - TP6 的
Db::table()->where()->find()是同步阻塞;TP8 同样写法在协程上下文中会自动转为异步,但若混用file_get_contents等非协程函数,会导致整个协程挂起
PHP-FPM 配置中哪些参数真影响 ThinkPHP 响应速度
关键不在 pm.max_children 多大,而在 pm.start_servers 和 pm.min_spare_servers 是否匹配实际请求波峰——设太高浪费内存,太低导致请求排队,slowlog 里出现 [pool www] child 12345 said into slowlog 就是典型信号。
使用场景:日均 PV 10 万左右的后台系统,PHP 版本 8.1,TP6.3,MySQL 8.0。
立即学习“PHP免费学习笔记(深入)”;
-
opcache.enable=1必须开,但opcache.validate_timestamps=0在开发环境要关,否则改代码不生效 -
realpath_cache_size=4096K推荐设为默认值 4M,TP 类自动加载路径深,缓存不足会频繁stat()系统调用 - 禁用
expose_php=Off不影响性能,但暴露 PHP 版本可能被扫描工具识别后针对性攻击
TP6 中开启 QueryLog 却没日志输出的三个原因
不是配置没生效,而是日志被拦截或写入路径不可写。TP6 的 Db::listen() 是内存级监听,不等于写文件;真正落地靠 log.channel.file 配置和 think\facade\Log 的触发时机。
常见错误现象:SQL log not found in runtime/log/,但 Db::getLastSql() 能取到 SQL。
- 检查
app_debug=true,关闭调试模式后Db::listen()默认不注册 -
log.level必须包含sql,例如['sql', 'info', 'error'],只写['info']不会记录 - 运行用户(如
www-data)对runtime/log/目录无写权限,chmod -R 755 runtime不够,得是775且组可写
Redis 缓存驱动在 TP6 和 TP8 中的初始化陷阱
TP6 的 cache.driver=redis 默认走 Predis,TP8 强制使用 ext-redis,两者连接参数名不一致:host/password 在 Predis 中有效,在 ext-redis 中要写成 hostname/auth,填错就静默回退到 file 缓存。
性能影响明显:Predis 是纯 PHP 实现,大量小 key 读写比 ext-redis 慢 30%~50%;但 ext-redis 不支持连接池自动回收,TP8 的 redis.pool.size 设太大反而引发 Redis server 的 maxclients 溢出。
- TP6 中
cache.redis.timeout=0表示永不超时,TP8 中该参数已移除,改用redis.options.timeout - TP8 的
Cache::store('redis')->get('key')若 key 不存在,返回null;TP6 默认返回false,业务里用=== false判断会失效 - 本地开发用 Docker Redis 时,TP8 必须把
redis.host设为宿主机网关(如172.17.0.1),不能写localhost,否则容器内解析失败
协程环境下 Redis 连接复用比想象中脆弱——哪怕只是中间加了一行 sleep(1),就可能导致连接被池误判为超时释放。这点在压测时才暴露,日常单请求几乎看不出问题。
本文共计1101个文字,预计阅读时间需要5分钟。
TP6是稳定版主分支,TP8(即ThinkPHP 8.0)是2024年初发布的全新架构,底层彻底切换为Swoole协程+支持异步,默认不兼容传统FPM模式。性能提升显著,在集中共享在高峰并发I/O场景,如大量Redis查询、HTTP微服务调用等;但对比纯模板渲染或简单CRUD,TP8因协程调度开销慢于TP6。
常见错误现象:Call to undefined function think\facade\Db() —— 这是 TP8 中废弃了全局门面,必须改用 think\db\Connection 或注入方式获取实例。
- TP6 默认运行在 PHP-FPM 下,兼容所有主机环境;TP8 要求 Swoole ≥ 5.1 且必须启用
enable_coroutine=1 - TP8 的
config('database')返回的是协程安全的连接池配置,不是原始数组,直接var_dump看不到实际参数 - TP6 的
Db::table()->where()->find()是同步阻塞;TP8 同样写法在协程上下文中会自动转为异步,但若混用file_get_contents等非协程函数,会导致整个协程挂起
PHP-FPM 配置中哪些参数真影响 ThinkPHP 响应速度
关键不在 pm.max_children 多大,而在 pm.start_servers 和 pm.min_spare_servers 是否匹配实际请求波峰——设太高浪费内存,太低导致请求排队,slowlog 里出现 [pool www] child 12345 said into slowlog 就是典型信号。
使用场景:日均 PV 10 万左右的后台系统,PHP 版本 8.1,TP6.3,MySQL 8.0。
立即学习“PHP免费学习笔记(深入)”;
-
opcache.enable=1必须开,但opcache.validate_timestamps=0在开发环境要关,否则改代码不生效 -
realpath_cache_size=4096K推荐设为默认值 4M,TP 类自动加载路径深,缓存不足会频繁stat()系统调用 - 禁用
expose_php=Off不影响性能,但暴露 PHP 版本可能被扫描工具识别后针对性攻击
TP6 中开启 QueryLog 却没日志输出的三个原因
不是配置没生效,而是日志被拦截或写入路径不可写。TP6 的 Db::listen() 是内存级监听,不等于写文件;真正落地靠 log.channel.file 配置和 think\facade\Log 的触发时机。
常见错误现象:SQL log not found in runtime/log/,但 Db::getLastSql() 能取到 SQL。
- 检查
app_debug=true,关闭调试模式后Db::listen()默认不注册 -
log.level必须包含sql,例如['sql', 'info', 'error'],只写['info']不会记录 - 运行用户(如
www-data)对runtime/log/目录无写权限,chmod -R 755 runtime不够,得是775且组可写
Redis 缓存驱动在 TP6 和 TP8 中的初始化陷阱
TP6 的 cache.driver=redis 默认走 Predis,TP8 强制使用 ext-redis,两者连接参数名不一致:host/password 在 Predis 中有效,在 ext-redis 中要写成 hostname/auth,填错就静默回退到 file 缓存。
性能影响明显:Predis 是纯 PHP 实现,大量小 key 读写比 ext-redis 慢 30%~50%;但 ext-redis 不支持连接池自动回收,TP8 的 redis.pool.size 设太大反而引发 Redis server 的 maxclients 溢出。
- TP6 中
cache.redis.timeout=0表示永不超时,TP8 中该参数已移除,改用redis.options.timeout - TP8 的
Cache::store('redis')->get('key')若 key 不存在,返回null;TP6 默认返回false,业务里用=== false判断会失效 - 本地开发用 Docker Redis 时,TP8 必须把
redis.host设为宿主机网关(如172.17.0.1),不能写localhost,否则容器内解析失败
协程环境下 Redis 连接复用比想象中脆弱——哪怕只是中间加了一行 sleep(1),就可能导致连接被池误判为超时释放。这点在压测时才暴露,日常单请求几乎看不出问题。

