今天翻到一个五年前自己写的项目,看着看着就笑了,笑着笑着就沉默了。一个用户状态判断,用了五种不同的写法——有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案例

我去年给客户写了个内部客服助手。用户在前台问:“帮我查一下上月销售额最高的三个商品。”

流程是这样的:

  1. PHP接收用户输入,拼Prompt调OpenAI API

  2. AI返回一段意图识别结果和参数

  3. PHP根据意图调用对应的Service,查数据库

  4. 把查询结果再拼Prompt,让AI生成自然语言回答

  5. 存日志、返前端

整个过程里,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也帮不了你,只能靠日复一日的自律。

上周重构完那个五年前的“屎山”,我在代码里加了一行注释:

“写代码的时候,想象一下接手你工作的人是个知道你住哪的暴力狂。”

这话有点糙,但理不糙。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐