那些年我们写过的“入门代码”:我终于学会了和PHP“讲和”
回顾这几年的变化,PHP确实变了很多——JIT、Fibers、Enums、Readonly、Attributes、FrankenPHP、AI集成。但真正让我觉得“这语言还能再战十年”的,不是这些新特性本身,而是它们背后的逻辑
今天翻到一个五年前自己写的项目,看着看着就笑了,笑着笑着就沉默了。一个用户状态判断,用了五种不同的写法——有if ($status == 1),有if ($status === 'active'),还有switch ($status)里混着case 2:和case 'pending'。更离谱的是,同一个“已发布”状态,在三个文件里分别叫'published'、'publish'和'PUBLISHED'。
五年后的今天,PHP 8.5已经发布了,RFC里还在讨论8.6的新特性。但打开很多公司的代码库,依然能看到这种“考古现场”。今天想聊的不是那些高大上的架构,而是我们每天都要面对的事——怎么写出一份让半年后的自己还能看懂的代码。
一、类型安全:不是装逼,是救命
1. 从“魔法值”到Enum:一个血泪史
先说个真事。去年线上出了个P0故障:一批文章莫名其妙进了“审核中”状态,发不出去。查了两小时,最后发现是某位同事在代码里写了:
if ($article->status == 'review') {
// 送审逻辑
}
而另一个地方,状态是从数据库查出来的,值是'revieew'——没错,多打了一个e。这个typo发生在三个月前的一次数据迁移脚本里。三个月,三千篇文章,全部卡在“审核中”,没人发现。
PHP 8.1引入的Enum,就是来终结这种悲剧的:
enum ArticleStatus: string {
case Draft = 'draft';
case Review = 'review';
case Published = 'published';
public function label(): string {
return match($this) {
self::Draft => '📝 草稿',
self::Review => '🔍 审核中',
self::Published => '🚀 已发布',
};
}
}
// 使用的时候
public function updateStatus(ArticleStatus $status): void {
$this->status = $status;
}
现在如果有人传'revieew',PHP直接报TypeError,连数据库都到不了。Enum的真正价值,是把错误拦截在编译阶段,而不是让它们成为生产环境的“定时炸弹”。
2. Readonly:别再让我背锅了
另一个让我又爱又恨的特性是readonly类(PHP 8.2引入)。
以前写DTO(数据传输对象),最怕的就是有人在中途乱改属性。你费尽心机构造好的对象,传到某个service里,人家顺手$user->email = 'hacker@evil.com',然后一路传下去,查错查到死。
现在好了:
readonly class UserDTO {
public function __construct(
public string $email,
public string $name,
public UserRole $role,
) {}
}
// 谁敢改?改了就是Fatal Error
$dto->email = 'new@email.com'; // Cannot modify readonly property!
有个细节要注意:readonly只保证属性不能被重新赋值,但如果属性本身是对象,那个对象的内部状态还是能改的。所以配合DateTimeImmutable这类不可变对象使用效果最佳。
二、常驻内存:PHP也可以“不重启”
聊完代码质量,再说说这两年让我最兴奋的变化——PHP开始真正拥抱常驻内存了。
传统的PHP-FPM模式是“共享无”架构:每个请求来,PHP从头开始加载框架、创建对象、执行代码,请求结束,一切销毁。好处是简单、隔离性好,坏处是——每次都在重复造轮子。框架的bootstrap过程占用了大量CPU时间,尤其是Laravel这类重型框架。
1. FrankenPHP:把PHP变成应用服务器
最近在折腾的一个项目叫FrankenPHP,它是基于Caddy服务器写的,能把PHP直接嵌入到服务器进程里。最牛的是它的“worker模式”:
-
传统模式:请求 → 加载框架 → 执行业务 → 销毁
-
worker模式:启动时加载一次框架 → 内存里等着 → 请求来了直接跑业务
性能差距有多大?官方数据说,在Laravel项目里,worker模式能把响应时间砍掉一半以上。我自己的测试,一个带数据库查询的接口,从120ms降到了45ms。
接入也很简单,Laravel用Octane,Symfony有对应包:
// 安装 Laravel Octane
composer require laravel/octane
php artisan octane:install --server=frankenphp
php artisan octane:start --server=frankenphp
完事儿。就这么简单。
2. 但要注意:静态变量不再是“安全区”
常驻内存有个坑:静态变量会在请求间共享 。以前写代码,静态变量只在当前请求有效,没人管。现在得小心了:
class RequestCounter {
public static int $count = 0;
public static function increment(): int {
return ++self::$count; // 第一个请求返回1,第二个返回2!
}
}
解决方式有几种:一是用框架提供的请求隔离机制(比如Laravel Octane会自动重置某些状态);二是设置max_requests参数,让worker处理一定数量请求后自动重启;三是严格审查代码,把不该共享的状态清理掉。
三、AI时代:PHP的新战场
最后聊聊大家都在焦虑的事:AI来了,PHP是不是要完?
我的答案是:恰恰相反,AI让PHP变得更值钱了 。
1. AI从“模型”走向“系统”
2026年,企业关心的不再是“训练一个模型”,而是“怎么把AI用到现有系统里”。这就涉及一堆事:
-
用户发来一句话 → 怎么解析意图?
-
需要查数据库 → 怎么生成SQL?权限怎么控制?
-
调用大模型API → 超时怎么处理?限流怎么做?
-
AI返回结果 → 怎么存?怎么展示?怎么审计?
这些活儿,Python不擅长,Java太重,恰恰是PHP的主场 。
2. 一个真实的Agent案例
我去年给客户写了个内部客服助手。用户在前台问:“帮我查一下上月销售额最高的三个商品。”
流程是这样的:
-
PHP接收用户输入,拼Prompt调OpenAI API
-
AI返回一段意图识别结果和参数
-
PHP根据意图调用对应的Service,查数据库
-
把查询结果再拼Prompt,让AI生成自然语言回答
-
存日志、返前端
整个过程里,AI只是个“大脑”,PHP是“身体”——负责感知、行动、记忆 。
3. PHP开发者需要学什么?
不是学PyTorch,不是学反向传播,而是学:

-
怎么调API(Guzzle、异步请求、重试机制)
-
怎么设计Prompt(这玩意儿现在是个正经技能)
-
怎么处理流式响应(Server-Sent Events在PHP里怎么玩)
-
怎么防Prompt注入(跟防SQL注入一个思路)
-
怎么审计AI行为(日志、监控、回滚)
这些本来就是我们的老本行,只是换了个马甲。
四、写在最后:基本功才是护城河
回顾这几年的变化,PHP确实变了很多——JIT、Fibers、Enums、Readonly、Attributes、FrankenPHP、AI集成。但真正让我觉得“这语言还能再战十年”的,不是这些新特性本身,而是它们背后的逻辑:
-
类型系统越来越强,帮我们拦截低级错误
-
性能工具越来越多,让PHP也能玩高并发
-
生态越来越开放,能无缝对接AI、云原生
但无论工具怎么变,基本功永远是护城河:
-
变量命名有没有意义?
-
函数是不是只干一件事?
-
异常处理是不是全覆盖?
-
日志是不是能还原现场?
这些事,Enum帮不了你,JIT也帮不了你,只能靠日复一日的自律。
上周重构完那个五年前的“屎山”,我在代码里加了一行注释:
“写代码的时候,想象一下接手你工作的人是个知道你住哪的暴力狂。”
这话有点糙,但理不糙。
更多推荐



所有评论(0)