<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Resmic's | BLOG</title><link>https://blog.resmic.cn/</link><description>个人博客</description><item><title>PHP 8.4 新特性全解析：属性钩子、非对称可见性与HTML5解析器实战</title><link>https://blog.resmic.cn/post/266.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260517080722177897644276895.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;一、PHP 8.4 重大升级概览&lt;/h2&gt;&lt;p&gt;PHP 8.4 于 2024 年 11 月正式发布，是 PHP 近年来功能最丰富的版本之一。本次更新引入了属性钩子（Property Hooks）、非对称可见性（Asymmetric Visibility）、全新的 HTML5 解析器以及大量数组操作函数，大幅提升了开发效率与语言表达力。&lt;/p&gt;&lt;p&gt;本文将深入剖析 PHP 8.4 的核心新特性，配合完整代码示例，帮助你快速掌握并应用于实际项目中。&lt;/p&gt;&lt;h2&gt;二、属性钩子（Property Hooks）：告别冗余 Getter/Setter&lt;/h2&gt;&lt;p&gt;属性钩子是 PHP 8.4 最受关注的特性，灵感来自 C# 和 Kotlin。它允许在属性定义时直接内联逻辑，无需手动编写大量 getter/setter 方法。&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

class&amp;nbsp;User&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$fullName&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;$this-&amp;gt;firstName&amp;nbsp;.&amp;nbsp;&amp;#39;&amp;nbsp;&amp;#39;&amp;nbsp;.&amp;nbsp;$this-&amp;gt;lastName;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$email&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;=&amp;gt;&amp;nbsp;strtolower($this-&amp;gt;_email);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!filter_var($value,&amp;nbsp;FILTER_VALIDATE_EMAIL))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw&amp;nbsp;new&amp;nbsp;\InvalidArgumentException(&amp;quot;Invalid&amp;nbsp;email:&amp;nbsp;$value&amp;quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;_email&amp;nbsp;=&amp;nbsp;$value;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$firstName,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$lastName,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$_email&amp;nbsp;=&amp;nbsp;&amp;#39;&amp;#39;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{}
}

$user&amp;nbsp;=&amp;nbsp;new&amp;nbsp;User(&amp;#39;张&amp;#39;,&amp;nbsp;&amp;#39;伟&amp;#39;);
$user-&amp;gt;email&amp;nbsp;=&amp;nbsp;&amp;#39;zhang@example.com&amp;#39;;
echo&amp;nbsp;$user-&amp;gt;fullName;&amp;nbsp;&amp;nbsp;//&amp;nbsp;张&amp;nbsp;伟
echo&amp;nbsp;$user-&amp;gt;email;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;zhang@example.com&lt;/pre&gt;&lt;p&gt;属性钩子支持 &lt;code&gt;get&lt;/code&gt; 和 &lt;code&gt;set&lt;/code&gt; 两种形式，可单独使用也可组合，简洁箭头语法 &lt;code&gt;get =&amp;gt;&lt;/code&gt; 适用于单行表达式。&lt;/p&gt;&lt;h2&gt;三、非对称可见性（Asymmetric Visibility）&lt;/h2&gt;&lt;p&gt;PHP 8.4 新增了属性读写分离的可见性控制，让你可以对外公开读取、对内限制写入，实现更优雅的封装。&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

class&amp;nbsp;BankAccount&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;公开读取，私有写入
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;private(set)&amp;nbsp;float&amp;nbsp;$balance&amp;nbsp;=&amp;nbsp;0.0;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;公开读取，protected&amp;nbsp;写入
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;protected(set)&amp;nbsp;string&amp;nbsp;$ownerId;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(string&amp;nbsp;$ownerId)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;ownerId&amp;nbsp;=&amp;nbsp;$ownerId;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;deposit(float&amp;nbsp;$amount):&amp;nbsp;void&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;($amount&amp;nbsp;&amp;lt;=&amp;nbsp;0)&amp;nbsp;throw&amp;nbsp;new&amp;nbsp;\InvalidArgumentException(&amp;#39;Amount&amp;nbsp;must&amp;nbsp;be&amp;nbsp;positive&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;balance&amp;nbsp;+=&amp;nbsp;$amount;&amp;nbsp;&amp;nbsp;//&amp;nbsp;内部可写
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;withdraw(float&amp;nbsp;$amount):&amp;nbsp;void&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;($amount&amp;nbsp;&amp;gt;&amp;nbsp;$this-&amp;gt;balance)&amp;nbsp;throw&amp;nbsp;new&amp;nbsp;\RuntimeException(&amp;#39;Insufficient&amp;nbsp;funds&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;balance&amp;nbsp;-=&amp;nbsp;$amount;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$account&amp;nbsp;=&amp;nbsp;new&amp;nbsp;BankAccount(&amp;#39;user_001&amp;#39;);
$account-&amp;gt;deposit(1000.0);
echo&amp;nbsp;$account-&amp;gt;balance;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;1000.0&amp;nbsp;—&amp;nbsp;可读
//&amp;nbsp;$account-&amp;gt;balance&amp;nbsp;=&amp;nbsp;9999;&amp;nbsp;&amp;nbsp;//&amp;nbsp;Fatal&amp;nbsp;Error&amp;nbsp;—&amp;nbsp;外部不可写&lt;/pre&gt;&lt;p&gt;这一特性彻底解决了以往需要写一堆 &lt;code&gt;getBalance()&lt;/code&gt; 方法的问题，代码更干净，意图更明确。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;public private(set)&lt;/code&gt;：任何地方可读，仅当前类可写&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;public protected(set)&lt;/code&gt;：任何地方可读，当前类和子类可写&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;protected private(set)&lt;/code&gt;：子类可读，仅当前类可写&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;四、全新数组操作函数&lt;/h2&gt;&lt;p&gt;PHP 8.4 新增了一批非常实用的数组函数，减少了许多常见场景中的模板代码。&lt;/p&gt;&lt;h3&gt;4.1 array_find 与 array_find_key&lt;/h3&gt;&lt;pre&gt;&amp;lt;?php

$users&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;id&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;1,&amp;nbsp;&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;张三&amp;#39;,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;admin&amp;#39;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;id&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;2,&amp;nbsp;&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;李四&amp;#39;,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;editor&amp;#39;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;id&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;3,&amp;nbsp;&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;王五&amp;#39;,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;admin&amp;#39;],
];

//&amp;nbsp;array_find：返回第一个满足条件的元素值
$admin&amp;nbsp;=&amp;nbsp;array_find($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;role&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;admin&amp;#39;);
//&amp;nbsp;[&amp;#39;id&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;1,&amp;nbsp;&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;张三&amp;#39;,&amp;nbsp;&amp;#39;role&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;admin&amp;#39;]

//&amp;nbsp;array_find_key：返回第一个满足条件的键名
$key&amp;nbsp;=&amp;nbsp;array_find_key($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;name&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;李四&amp;#39;);
//&amp;nbsp;1

//&amp;nbsp;array_any：只要有一个满足就返回&amp;nbsp;true
$hasAdmin&amp;nbsp;=&amp;nbsp;array_any($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;role&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;admin&amp;#39;);&amp;nbsp;&amp;nbsp;//&amp;nbsp;true

//&amp;nbsp;array_all：所有元素满足才返回&amp;nbsp;true
$allActive&amp;nbsp;=&amp;nbsp;array_all($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;isset($u[&amp;#39;id&amp;#39;]));&amp;nbsp;&amp;nbsp;//&amp;nbsp;true&lt;/pre&gt;&lt;h3&gt;4.2 array_zip 与更多组合技&lt;/h3&gt;&lt;pre&gt;&amp;lt;?php

//&amp;nbsp;实用组合：找出所有&amp;nbsp;admin&amp;nbsp;的名字
$adminNames&amp;nbsp;=&amp;nbsp;array_map(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;name&amp;#39;],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;array_filter($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;role&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;admin&amp;#39;)
);
//&amp;nbsp;[&amp;#39;张三&amp;#39;,&amp;nbsp;&amp;#39;王五&amp;#39;]

//&amp;nbsp;或使用&amp;nbsp;array_find&amp;nbsp;+&amp;nbsp;array_map&amp;nbsp;链式处理
$firstAdminName&amp;nbsp;=&amp;nbsp;array_find($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;role&amp;#39;]&amp;nbsp;===&amp;nbsp;&amp;#39;admin&amp;#39;)[&amp;#39;name&amp;#39;]&amp;nbsp;??&amp;nbsp;null;
//&amp;nbsp;&amp;#39;张三&amp;#39;&lt;/pre&gt;&lt;h2&gt;五、全新 HTML5 解析器（基于 Lexbor）&lt;/h2&gt;&lt;p&gt;PHP 8.4 引入了基于 &lt;a href=&quot;https://github.com/lexbor/lexbor&quot;&gt;Lexbor&lt;/a&gt; 的新 HTML5 解析器，通过 &lt;code&gt;Dom\HTMLDocument&lt;/code&gt; 和 &lt;code&gt;Dom\XMLDocument&lt;/code&gt; 类提供，取代了老旧的 &lt;code&gt;DOMDocument&lt;/code&gt;，完全符合 HTML5 规范。&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

//&amp;nbsp;旧方式（PHP&amp;nbsp;8.3&amp;nbsp;及之前）
$oldDom&amp;nbsp;=&amp;nbsp;new&amp;nbsp;DOMDocument();
@$oldDom-&amp;gt;loadHTML(&amp;#39;&amp;lt;p&amp;gt;Hello&amp;nbsp;&amp;lt;b&amp;gt;World&amp;lt;/b&amp;gt;&amp;lt;/p&amp;gt;&amp;#39;);

//&amp;nbsp;新方式（PHP&amp;nbsp;8.4）
$html&amp;nbsp;=&amp;nbsp;&amp;#39;&amp;lt;!DOCTYPE&amp;nbsp;html&amp;gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;article&amp;nbsp;id=&amp;quot;main&amp;quot;&amp;gt;&amp;lt;p&amp;gt;PHP&amp;nbsp;8.4&amp;nbsp;&amp;lt;strong&amp;gt;很强！&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/article&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39;;

$doc&amp;nbsp;=&amp;nbsp;Dom\HTMLDocument::createFromString($html,&amp;nbsp;LIBXML_NOERROR);
$article&amp;nbsp;=&amp;nbsp;$doc-&amp;gt;getElementById(&amp;#39;main&amp;#39;);
echo&amp;nbsp;$article-&amp;gt;textContent;&amp;nbsp;&amp;nbsp;//&amp;nbsp;PHP&amp;nbsp;8.4&amp;nbsp;很强！

//&amp;nbsp;支持&amp;nbsp;querySelector（CSS&amp;nbsp;选择器！）
$strong&amp;nbsp;=&amp;nbsp;$doc-&amp;gt;querySelector(&amp;#39;article&amp;nbsp;strong&amp;#39;);
echo&amp;nbsp;$strong-&amp;gt;textContent;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;很强！

$allParagraphs&amp;nbsp;=&amp;nbsp;$doc-&amp;gt;querySelectorAll(&amp;#39;p&amp;#39;);
foreach&amp;nbsp;($allParagraphs&amp;nbsp;as&amp;nbsp;$p)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;$p-&amp;gt;innerHTML&amp;nbsp;.&amp;nbsp;&amp;quot;\n&amp;quot;;
}

//&amp;nbsp;从文件或&amp;nbsp;URL&amp;nbsp;加载
$docFromFile&amp;nbsp;=&amp;nbsp;Dom\HTMLDocument::createFromFile(&amp;#39;/path/to/page.html&amp;#39;);&lt;/pre&gt;&lt;p&gt;新解析器支持 &lt;code&gt;querySelector&lt;/code&gt; / &lt;code&gt;querySelectorAll&lt;/code&gt; CSS 选择器，无需再引入 Symfony DomCrawler 或 phpQuery 等第三方库来做基础 HTML 解析，非常适合爬虫、邮件模板处理、内容抓取等场景。&lt;/p&gt;&lt;h2&gt;六、其他值得关注的新特性&lt;/h2&gt;&lt;h3&gt;6.1 new 表达式不再需要括号&lt;/h3&gt;&lt;pre&gt;&amp;lt;?php

//&amp;nbsp;PHP&amp;nbsp;8.3&amp;nbsp;及之前
$length&amp;nbsp;=&amp;nbsp;(new&amp;nbsp;Collection([1,&amp;nbsp;2,&amp;nbsp;3]))-&amp;gt;count();

//&amp;nbsp;PHP&amp;nbsp;8.4：直接链式调用，无需括号包裹
$length&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Collection([1,&amp;nbsp;2,&amp;nbsp;3])-&amp;gt;count();

//&amp;nbsp;在方法链中的应用
$result&amp;nbsp;=&amp;nbsp;new&amp;nbsp;QueryBuilder()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;table(&amp;#39;users&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;where(&amp;#39;status&amp;#39;,&amp;nbsp;&amp;#39;active&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;orderBy(&amp;#39;created_at&amp;#39;,&amp;nbsp;&amp;#39;DESC&amp;#39;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;gt;get();&lt;/pre&gt;&lt;h3&gt;6.2 JIT 编译器改进与性能提升&lt;/h3&gt;&lt;p&gt;PHP 8.4 对 JIT（Just-In-Time）编译器进行了重大重构，新的 IR（中间表示）框架使 JIT 编译更加稳定高效：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;CPU 密集型任务性能提升约 &lt;strong&gt;5-10%&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;JIT 生成代码质量更高，更易于调试&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;新增 &lt;code&gt;tracing&lt;/code&gt; 和 &lt;code&gt;function&lt;/code&gt; JIT 模式配置选项&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;修复了多个 JIT 相关的内存安全问题&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;6.3 Lazy Objects（惰性对象）&lt;/h3&gt;&lt;pre&gt;&amp;lt;?php

class&amp;nbsp;DatabaseConnection&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$host,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;int&amp;nbsp;$port,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$dbname,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;模拟耗时初始化
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;Connecting&amp;nbsp;to&amp;nbsp;{$this-&amp;gt;host}:{$this-&amp;gt;port}/{$this-&amp;gt;dbname}\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;query(string&amp;nbsp;$sql):&amp;nbsp;array&amp;nbsp;{&amp;nbsp;/*&amp;nbsp;...&amp;nbsp;*/&amp;nbsp;return&amp;nbsp;[];&amp;nbsp;}
}

//&amp;nbsp;创建惰性代理&amp;nbsp;—&amp;nbsp;实际对象尚未初始化
$reflector&amp;nbsp;=&amp;nbsp;new&amp;nbsp;ReflectionClass(DatabaseConnection::class);
$proxy&amp;nbsp;=&amp;nbsp;$reflector-&amp;gt;newLazyProxy(function()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;new&amp;nbsp;DatabaseConnection(&amp;#39;localhost&amp;#39;,&amp;nbsp;3306,&amp;nbsp;&amp;#39;mydb&amp;#39;);
});

//&amp;nbsp;此时尚未输出&amp;nbsp;&amp;quot;Connecting&amp;nbsp;to...&amp;quot;
echo&amp;nbsp;&amp;quot;Proxy&amp;nbsp;created\n&amp;quot;;

//&amp;nbsp;只有真正使用时才初始化
$result&amp;nbsp;=&amp;nbsp;$proxy-&amp;gt;query(&amp;#39;SELECT&amp;nbsp;1&amp;#39;);
//&amp;nbsp;现在才输出&amp;nbsp;&amp;quot;Connecting&amp;nbsp;to&amp;nbsp;localhost:3306/mydb&amp;quot;&lt;/pre&gt;&lt;p&gt;惰性对象特别适合依赖注入容器、ORM 延迟加载、服务定位器等场景，可以显著减少应用启动时的初始化开销。&lt;/p&gt;&lt;h2&gt;七、升级建议与兼容性注意事项&lt;/h2&gt;&lt;p&gt;PHP 8.4 虽然功能强大，升级前需关注以下破坏性变更：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;隐式 nullable 类型弃用&lt;/strong&gt;：&lt;code&gt;function foo(Type $x = null)&lt;/code&gt; 需改为 &lt;code&gt;function foo(?Type $x = null)&lt;/code&gt;，PHP 8.4 发出弃用警告，PHP 9.0 将直接报错&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GMP 扩展变更&lt;/strong&gt;：&lt;code&gt;GMP&lt;/code&gt; 对象不再支持动态属性&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;LDAP 扩展废弃&lt;/strong&gt;：若干旧 API 标记弃用&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;MySQLnd 变更&lt;/strong&gt;：&lt;code&gt;mysqli_ping()&lt;/code&gt; 等函数行为调整&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;升级步骤建议：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;在测试环境先用 &lt;code&gt;php -l&lt;/code&gt; 批量检查语法兼容性&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;开启 &lt;code&gt;E_DEPRECATED&lt;/code&gt; 日志，修复所有弃用警告&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;运行完整测试套件（PHPUnit）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;使用 &lt;a href=&quot;https://github.com/rectorphp/rector&quot;&gt;Rector&lt;/a&gt; 自动化迁移工具处理大量重复修改&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;灰度上线，监控错误率&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;PHP 8.4 是一次值得升级的大版本，属性钩子、非对称可见性、新 HTML5 解析器等特性将显著提升代码可读性和开发效率。建议在项目的下一个迭代周期规划升级，早用早受益。&lt;/p&gt;</description><pubDate>Sun, 17 May 2026 08:07:36 +0800</pubDate></item><item><title>PHP 8.4 核心新特性深度解析：属性钩子、懒加载对象与新增数组函数实战指南</title><link>https://blog.resmic.cn/post/265.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260516080708177889002840355.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;PHP 8.4 正式发布：为什么值得升级？&lt;/h2&gt;&lt;p&gt;PHP 8.4 于 2024 年 11 月正式发布，带来了多项开发者期待已久的语言特性。这次升级延续了 PHP 8.x 系列的现代化步伐，让 PHP 在类型系统、面向对象设计和运行时性能等维度都有了质的提升。&lt;/p&gt;&lt;p&gt;如果你还在使用 PHP 8.1 或 8.2，现在正是评估升级的好时机。本文将用实际代码示例带你快速了解最值得关注的新特性。&lt;/p&gt;&lt;h2&gt;属性钩子（Property Hooks）：告别繁琐的 getter/setter&lt;/h2&gt;&lt;p&gt;这是 PHP 8.4 最受期待的特性之一。过去我们需要为每个属性手写 &lt;code&gt;getXxx()&lt;/code&gt; 和 &lt;code&gt;setXxx()&lt;/code&gt; 方法，代码冗余且难以维护。属性钩子让你直接在属性声明处定义读写逻辑：&lt;/p&gt;&lt;pre&gt;class&amp;nbsp;User&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$fullName&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;=&amp;gt;&amp;nbsp;$this-&amp;gt;firstName&amp;nbsp;.&amp;nbsp;&amp;#39;&amp;nbsp;&amp;#39;&amp;nbsp;.&amp;nbsp;$this-&amp;gt;lastName;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set(string&amp;nbsp;$value)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[$this-&amp;gt;firstName,&amp;nbsp;$this-&amp;gt;lastName]&amp;nbsp;=&amp;nbsp;explode(&amp;#39;&amp;nbsp;&amp;#39;,&amp;nbsp;$value,&amp;nbsp;2);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$firstName,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$lastName
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{}
}

$user&amp;nbsp;=&amp;nbsp;new&amp;nbsp;User(&amp;#39;张&amp;#39;,&amp;nbsp;&amp;#39;三&amp;#39;);
echo&amp;nbsp;$user-&amp;gt;fullName;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;输出：张&amp;nbsp;三
$user-&amp;gt;fullName&amp;nbsp;=&amp;nbsp;&amp;#39;李&amp;nbsp;四&amp;#39;;&amp;nbsp;//&amp;nbsp;自动分割
echo&amp;nbsp;$user-&amp;gt;firstName;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;输出：李&lt;/pre&gt;&lt;p&gt;属性钩子同样支持接口定义，这意味着你可以在接口层面约束钩子行为，大幅提升代码的可维护性。&lt;/p&gt;&lt;h2&gt;懒加载对象（Lazy Objects）：按需初始化的优雅方案&lt;/h2&gt;&lt;p&gt;PHP 8.4 在反射 API 中引入了懒加载对象支持，非常适合依赖注入容器、ORM 延迟加载等场景：&lt;/p&gt;&lt;pre&gt;class&amp;nbsp;DatabaseConnection&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$dsn,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$username,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;string&amp;nbsp;$password
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;假设这里有耗时的初始化操作
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;连接数据库中...\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;query(string&amp;nbsp;$sql):&amp;nbsp;array&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;[];&amp;nbsp;//&amp;nbsp;实际查询逻辑
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

//&amp;nbsp;创建懒加载对象——此时构造函数尚未执行
$reflector&amp;nbsp;=&amp;nbsp;new&amp;nbsp;ReflectionClass(DatabaseConnection::class);
$db&amp;nbsp;=&amp;nbsp;$reflector-&amp;gt;newLazyGhost(function&amp;nbsp;(DatabaseConnection&amp;nbsp;$obj)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$obj-&amp;gt;__construct(&amp;#39;mysql:host=localhost&amp;#39;,&amp;nbsp;&amp;#39;root&amp;#39;,&amp;nbsp;&amp;#39;secret&amp;#39;);
});

echo&amp;nbsp;&amp;quot;对象已创建，但未初始化\n&amp;quot;;
//&amp;nbsp;只有真正使用时才触发初始化
$result&amp;nbsp;=&amp;nbsp;$db-&amp;gt;query(&amp;#39;SELECT&amp;nbsp;1&amp;#39;);
echo&amp;nbsp;&amp;quot;现在才连接数据库\n&amp;quot;;&lt;/pre&gt;&lt;p&gt;懒加载对象分为 Ghost 和 Proxy 两种模式，Ghost 模式直接初始化原对象，Proxy 模式则创建代理实例，各有适用场景。&lt;/p&gt;&lt;h2&gt;新增数组函数：array_find / array_find_key / array_any / array_all&lt;/h2&gt;&lt;p&gt;这四个新函数填补了 PHP 数组操作的长期空白，终于不用再写重复的 foreach 查找逻辑了：&lt;/p&gt;&lt;pre&gt;$users&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;张三&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;28,&amp;nbsp;&amp;#39;active&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;true],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;李四&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;35,&amp;nbsp;&amp;#39;active&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;false],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;王五&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;22,&amp;nbsp;&amp;#39;active&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;true],
];

//&amp;nbsp;array_find：找到第一个匹配元素
$adult&amp;nbsp;=&amp;nbsp;array_find($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;age&amp;#39;]&amp;nbsp;&amp;gt;=&amp;nbsp;30);
//&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;李四&amp;#39;,&amp;nbsp;&amp;#39;age&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;35,&amp;nbsp;&amp;#39;active&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;false]

//&amp;nbsp;array_find_key：找到第一个匹配元素的键
$key&amp;nbsp;=&amp;nbsp;array_find_key($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;!$u[&amp;#39;active&amp;#39;]);
//&amp;nbsp;1

//&amp;nbsp;array_any：是否存在至少一个匹配元素
$hasActive&amp;nbsp;=&amp;nbsp;array_any($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;active&amp;#39;]);
//&amp;nbsp;true

//&amp;nbsp;array_all：是否所有元素都匹配
$allActive&amp;nbsp;=&amp;nbsp;array_all($users,&amp;nbsp;fn($u)&amp;nbsp;=&amp;gt;&amp;nbsp;$u[&amp;#39;active&amp;#39;]);
//&amp;nbsp;false&lt;/pre&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;array_find&lt;/strong&gt;：类似 JavaScript 的 &lt;code&gt;Array.prototype.find()&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;array_find_key&lt;/strong&gt;：返回匹配元素的键而非值&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;array_any&lt;/strong&gt;：等价于 JS 的 &lt;code&gt;some()&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;array_all&lt;/strong&gt;：等价于 JS 的 &lt;code&gt;every()&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;其他值得关注的改进&lt;/h2&gt;&lt;p&gt;PHP 8.4 还包含了若干实用的小改进，提升日常开发体验：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;new 不再需要括号&lt;/strong&gt;：&lt;code&gt;$obj = new Foo()-&amp;gt;method()&lt;/code&gt; 现在合法，链式调用更流畅&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;#[\Deprecated] 属性&lt;/strong&gt;：可用于标记类、方法、常量为废弃，触发标准废弃警告&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;BCMath 对象 API&lt;/strong&gt;：新增 &lt;code&gt;BcMath\Number&lt;/code&gt; 类，支持运算符重载，让高精度计算代码更直观&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTML5 解析器&lt;/strong&gt;：&lt;code&gt;Dom\HTMLDocument&lt;/code&gt; 基于最新 HTML5 规范，替代旧的 &lt;code&gt;DOMDocument&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;PDO Driver 特定子类&lt;/strong&gt;：&lt;code&gt;PDO::connect()&lt;/code&gt; 现在直接返回 &lt;code&gt;Pdo\Mysql&lt;/code&gt;/&lt;code&gt;Pdo\Sqlite&lt;/code&gt; 等子类，类型更精确&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;//&amp;nbsp;new&amp;nbsp;不再需要括号示例
$length&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Stringable(&amp;#39;hello&amp;nbsp;world&amp;#39;)-&amp;gt;length();&amp;nbsp;//&amp;nbsp;假设有此方法

//&amp;nbsp;Deprecated&amp;nbsp;属性标记
class&amp;nbsp;LegacyApi&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#[\Deprecated(&amp;#39;请使用&amp;nbsp;newMethod()&amp;#39;)]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;oldMethod():&amp;nbsp;void&amp;nbsp;{}
}

//&amp;nbsp;BCMath&amp;nbsp;对象&amp;nbsp;API
use&amp;nbsp;BcMath\Number;
$a&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Number(&amp;#39;10.5&amp;#39;);
$b&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Number(&amp;#39;3.2&amp;#39;);
$result&amp;nbsp;=&amp;nbsp;$a&amp;nbsp;+&amp;nbsp;$b;&amp;nbsp;&amp;nbsp;//&amp;nbsp;运算符重载，结果为&amp;nbsp;Number(&amp;#39;13.7&amp;#39;)
echo&amp;nbsp;$result;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;13.7&lt;/pre&gt;&lt;h2&gt;升级建议与兼容性注意事项&lt;/h2&gt;&lt;p&gt;PHP 8.4 的不兼容变更相对较少，升级成本低。主要需要关注：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;隐式 nullable 类型已废弃&lt;/strong&gt;：&lt;code&gt;function foo(string $x = null)&lt;/code&gt; 需改为 &lt;code&gt;?string $x = null&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;E_STRICT 常量已移除&lt;/strong&gt;：若代码中有 &lt;code&gt;E_STRICT&lt;/code&gt; 引用需清理&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;部分 LDAP 函数已移除&lt;/strong&gt;：检查是否使用了废弃的 LDAP 函数&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;升级步骤建议：先在测试环境运行 &lt;code&gt;php -l&lt;/code&gt; 语法检测，再用 &lt;a href=&quot;https://phpstan.org/&quot; target=&quot;_blank&quot;&gt;PHPStan&lt;/a&gt; 或 Rector 的规则集做静态分析，识别废弃用法后再切换生产环境。&lt;/p&gt;&lt;p&gt;总体而言，PHP 8.4 是一次高质量的版本迭代，属性钩子和懒加载对象尤其值得在新项目中积极采用，能显著提升代码的可读性和设计质量。&lt;/p&gt;</description><pubDate>Sat, 16 May 2026 08:10:18 +0800</pubDate></item><item><title>PHP 8.3 新特性全面解析：类型系统、随机数API与性能优化实战</title><link>https://blog.resmic.cn/post/264.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260515080914177880375496570.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;&gt;&lt;/p&gt;

&lt;h2&gt;PHP 8.3 概览：值得升级的理由&lt;/h2&gt;
&lt;p&gt;PHP 8.3 于 2023 年 11 月正式发布，作为 PHP 8.x 系列的最新稳定版本，它在语言特性、类型系统和性能方面都带来了显著改进。如果你还在使用 PHP 8.0 或 8.1，现在是时候认真考虑迁移到 8.3 了。&lt;/p&gt;
&lt;p&gt;相比早期版本，PHP 8.3 在以下几个核心方向取得了突破：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;类型系统增强&lt;/strong&gt;：类型化类常量（Typed Class Constants）让代码更严谨&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;只读属性改进&lt;/strong&gt;：支持对只读属性进行初始化再赋值（Clone 场景）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;新的随机数 API&lt;/strong&gt;：Randomizer 类提供更安全、可测试的随机数生成&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;动态类常量获取&lt;/strong&gt;：支持通过变量访问类常量&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;性能提升&lt;/strong&gt;：OPcache 优化，实测吞吐量提升 5%-10%&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面我们逐一深入讲解这些特性，并结合真实项目场景给出最佳实践。&lt;/p&gt;

&lt;h2&gt;类型化类常量：让接口契约更严格&lt;/h2&gt;
&lt;p&gt;在 PHP 8.3 之前，类常量没有类型约束，容易出现意外的类型混用。8.3 引入了类型化类常量（Typed Class Constants），让常量拥有明确的类型声明。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
// PHP 8.3 之前：常量无类型限制
class Status {
    const ACTIVE = 1;       // int
    const LABEL  = 'active'; // 与 ACTIVE 语义无关联
}

// PHP 8.3：类型化类常量
class Status {
    const int    ACTIVE   = 1;
    const string LABEL    = 'active';
    const float  VERSION  = 8.3;
    const bool   IS_VALID = true;
}

// 接口中也支持类型化常量
interface Configurable {
    const string DEFAULT_LOCALE = 'zh-CN';
    const int    MAX_RETRY      = 3;
}

class App implements Configurable {
    // 实现必须匹配类型，否则抛出 TypeError
    const string DEFAULT_LOCALE = 'en-US'; // ✅ 合法
    const int    MAX_RETRY      = 5;        // ✅ 合法
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类型化常量的好处在于：继承类如果试图用不兼容的类型覆盖父类常量，PHP 会在编译阶段直接报错，而不是等到运行时才暴露问题。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
class Base {
    const int LIMIT = 100;
}

class Child extends Base {
    const string LIMIT = 'unlimited'; // Fatal error: 类型不兼容
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在大型项目中，建议将所有业务枚举常量都加上类型声明，这样 IDE 和静态分析工具（PHPStan、Psalm）可以提供更精准的检查。&lt;/p&gt;

&lt;h2&gt;只读属性增强：克隆场景的解决方案&lt;/h2&gt;
&lt;p&gt;PHP 8.1 引入了只读属性（readonly），但有一个痛点：只读属性一旦初始化就无法修改，导致克隆对象时无法更新属性值。PHP 8.3 通过允许在克隆（clone）操作中重新赋值来解决这个问题。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
class User {
    public function __construct(
        public readonly int    $id,
        public readonly string $name,
        public readonly string $email,
    ) {}
}

$user = new User(1, '张三', 'zhangsan@example.com');

// PHP 8.3 之前：无法修改只读属性，这种需求只能放弃使用 readonly
// $updated = clone $user; // clone 后无法改 email

// PHP 8.3：使用 clone with 语法修改只读属性
$updated = clone($user, email: 'new@example.com'); // 未来语法提案
// 目前实际可用的方式：在 __clone 中通过特定模式重置
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更实用的场景是结合值对象（Value Object）模式：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
// 推荐模式：使用 with 方法返回新实例
class Money {
    public function __construct(
        public readonly int    $amount,
        public readonly string $currency,
    ) {}

    public function withAmount(int $amount): static {
        $clone = clone $this;
        // PHP 8.3 允许在 clone 上下文中对 readonly 属性赋值
        $clone-&gt;amount = $amount;
        return $clone;
    }
}

$price  = new Money(100, 'CNY');
$double = $price-&gt;withAmount(200);
echo $double-&gt;amount;   // 200
echo $price-&gt;amount;    // 100 — 原对象不变
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这让不可变数据对象（Immutable DTO）的实现变得自然，无需再为了可克隆性而放弃 readonly。&lt;/p&gt;

&lt;h2&gt;新随机数 API：安全、可测试的随机性&lt;/h2&gt;
&lt;p&gt;PHP 8.2 引入了 &lt;code&gt;Random\Randomizer&lt;/code&gt; 类，8.3 进一步完善了相关 API，包括新增 &lt;code&gt;getBytesFromString()&lt;/code&gt;、&lt;code&gt;nextFloat()&lt;/code&gt; 等方法，让随机数生成更灵活、更易于单元测试。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
use Random\Randomizer;
use Random\Engine\Mt19937;
use Random\Engine\Secure;

// 生产环境：使用密码学安全引擎
$randomizer = new Randomizer(new Secure());

// 生成随机字节
$token = bin2hex($randomizer-&gt;getBytes(32));
echo $token; // 64位十六进制随机 token

// PHP 8.3 新增：从指定字符集中取随机字节
$charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$code    = $randomizer-&gt;getBytesFromString($charset, 8);
echo $code; // 例如：aB3kR7mX

// 生成范围内随机浮点数 (PHP 8.3 新增)
$float = $randomizer-&gt;nextFloat();         // [0.0, 1.0)
$float = $randomizer-&gt;getFloat(1.5, 9.5);  // [1.5, 9.5]

// 打乱数组
$items    = ['A', 'B', 'C', 'D', 'E'];
$shuffled = $randomizer-&gt;shuffleArray($items);

// 单元测试：使用固定种子保证可重复性
$seeded = new Randomizer(new Mt19937(42));
$result = $seeded-&gt;getInt(1, 100); // 固定种子，每次结果相同，便于测试
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;传统的 &lt;code&gt;rand()&lt;/code&gt;、&lt;code&gt;mt_rand()&lt;/code&gt; 不适合安全场景（如生成 token、验证码），而 &lt;code&gt;random_bytes()&lt;/code&gt; 虽然安全但功能有限。新的 &lt;code&gt;Randomizer&lt;/code&gt; API 既安全又灵活，是未来的最佳选择。&lt;/p&gt;

&lt;h2&gt;动态类常量获取与 json_validate 函数&lt;/h2&gt;
&lt;p&gt;PHP 8.3 支持通过变量动态访问类常量，告别了以前需要借助 &lt;code&gt;constant()&lt;/code&gt; 函数的繁琐写法。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
class Color {
    const string RED   = '#FF0000';
    const string GREEN = '#00FF00';
    const string BLUE  = '#0000FF';
}

// PHP 8.3 之前
$name  = 'RED';
$value = constant('Color::' . $name); // 需要用 constant()

// PHP 8.3：直接使用变量
$name  = 'GREEN';
$value = Color::{$name}; // '#00FF00' ✓

// 在枚举中同样适用
enum Direction {
    case North;
    case South;
    case East;
    case West;
}

$dir   = 'North';
$value = Direction::{$dir}; // Direction::North
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另一个非常实用的新增函数是 &lt;code&gt;json_validate()&lt;/code&gt;，它仅验证 JSON 字符串是否合法，而不进行解析，性能比 &lt;code&gt;json_decode()&lt;/code&gt; + 错误检查高得多：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php
// PHP 8.3 之前：验证 JSON 需要先解码
function isValidJson(string $str): bool {
    json_decode($str);
    return json_last_error() === JSON_ERROR_NONE;
}

// PHP 8.3：直接用 json_validate()
$validJson   = '{&quot;name&quot;:&quot;张三&quot;,&quot;age&quot;:30}';
$invalidJson = '{name:张三}';

var_dump(json_validate($validJson));   // bool(true)
var_dump(json_validate($invalidJson)); // bool(false)

// 支持指定最大嵌套深度
json_validate($validJson, depth: 5);  // 最多5层嵌套

// 实际场景：API 入参校验
function handleApiRequest(string $body): array {
    if (!json_validate($body)) {
        throw new InvalidArgumentException('请求体不是合法的 JSON');
    }
    return json_decode($body, true);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;性能优化与迁移实践&lt;/h2&gt;
&lt;p&gt;PHP 8.3 在底层做了多项性能优化，主要体现在：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;OPcache 改进&lt;/strong&gt;：改进了类型推断，生成更优化的字节码&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;JIT 稳定性提升&lt;/strong&gt;：修复了多个 JIT 相关 bug，对计算密集型应用提升明显&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;内存使用优化&lt;/strong&gt;：减少了字符串拷贝次数，降低了常见操作的内存开销&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fiber 改进&lt;/strong&gt;：协程相关功能更稳定，适合高并发异步场景&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从 PHP 8.1/8.2 迁移到 8.3 的步骤：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 1. 检查当前 PHP 版本
php -v

# 2. 用 PHP Compatibility Checker 扫描代码
composer require --dev phpcompatibility/php-compatibility
vendor/bin/phpcs --standard=PHPCompatibility --runtime-set testVersion 8.3 src/

# 3. 运行测试套件
composer test

# 4. 检查废弃警告（升级前先修复所有 Deprecated）
php -d error_reporting=E_ALL index.php 2&gt;&amp;1 | grep -i deprecated

# 5. 更新 Docker 基础镜像
# FROM php:8.2-fpm → FROM php:8.3-fpm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;值得注意的废弃变更：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;ldap_connect()&lt;/code&gt; 不再支持 host:port 格式，需拆分参数&lt;/li&gt;
  &lt;li&gt;部分 &lt;code&gt;DateTime&lt;/code&gt; 构造器行为调整，建议使用 &lt;code&gt;DateTimeImmutable&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;str_pad()&lt;/code&gt; 对多字节字符串的处理更严格，注意中文场景&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总体来说，PHP 8.3 的迁移成本极低，而收益显著。无论是代码质量、开发体验还是运行性能，都值得尽早升级。现在就把 &lt;code&gt;composer.json&lt;/code&gt; 中的 &lt;code&gt;&quot;php&quot;: &quot;&gt;=8.1&quot;&lt;/code&gt; 改为 &lt;code&gt;&quot;php&quot;: &quot;&gt;=8.3&quot;&lt;/code&gt;，开始享受新特性吧！&lt;/p&gt;
</description><pubDate>Fri, 15 May 2026 08:09:29 +0800</pubDate></item><item><title>Jetpack Compose 性能优化实战：从重组原理到 60fps 实践指南</title><link>https://blog.resmic.cn/post/263.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260514080821177871730110410.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;p&gt;Jetpack Compose 自正式发布以来，已成为 Android 声明式 UI 开发的标准选择。然而随着项目规模增大，许多开发者开始遭遇 Compose 的性能问题：卡顿、掉帧、不必要的重组（Recomposition）。本文从底层原理出发，系统讲解如何排查和优化 Compose 的渲染性能，帮助你将帧率稳定在 60fps 甚至 120fps。&lt;/p&gt;&lt;h2&gt;一、理解 Compose 的渲染三阶段&lt;/h2&gt;&lt;p&gt;要优化性能，首先要理解 Compose 的渲染流程。Compose 将 UI 渲染分为三个阶段：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Composition（组合）&lt;/strong&gt;：执行 Composable 函数，构建 UI 树（Slot Table）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Layout（布局）&lt;/strong&gt;：测量每个节点的尺寸与位置，单次遍历即可完成（相比 View 避免多次测量）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Drawing（绘制）&lt;/strong&gt;：将布局结果绘制到画布（Canvas）上&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;理解这三个阶段的关键点：不是每次 State 变化都会触发完整的三阶段。Compose 有一套智能跳过机制——如果某个 Composable 的输入没有变化，它可以被跳过（skipped）。这个跳过机制是性能优化的核心。&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;Compose&amp;nbsp;内部的跳过判断逻辑示意
//&amp;nbsp;如果所有参数都&amp;nbsp;&amp;quot;stable&amp;quot;&amp;nbsp;且值没变化，则跳过重组
@Composable
fun&amp;nbsp;UserCard(user:&amp;nbsp;User)&amp;nbsp;{&amp;nbsp;//&amp;nbsp;User&amp;nbsp;如果是&amp;nbsp;data&amp;nbsp;class，默认&amp;nbsp;stable
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Text(text&amp;nbsp;=&amp;nbsp;user.name)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Text(text&amp;nbsp;=&amp;nbsp;user.email)
}&lt;/pre&gt;&lt;h2&gt;二、重组（Recomposition）的陷阱与优化策略&lt;/h2&gt;&lt;p&gt;不必要的重组是 Compose 性能问题的头号原因。以下是常见的重组陷阱：&lt;/p&gt;&lt;h3&gt;陷阱1：Lambda 捕获导致重组扩散&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;❌&amp;nbsp;错误写法：每次父组件重组，onClick&amp;nbsp;都是新的&amp;nbsp;Lambda&amp;nbsp;实例
@Composable
fun&amp;nbsp;ParentComposable(items:&amp;nbsp;List&amp;lt;Item&amp;gt;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items.forEach&amp;nbsp;{&amp;nbsp;item&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ItemRow(item&amp;nbsp;=&amp;nbsp;item,&amp;nbsp;onClick&amp;nbsp;=&amp;nbsp;{&amp;nbsp;doSomething(item)&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

//&amp;nbsp;✅&amp;nbsp;正确写法：使用&amp;nbsp;remember&amp;nbsp;缓存&amp;nbsp;Lambda
@Composable
fun&amp;nbsp;ParentComposable(items:&amp;nbsp;List&amp;lt;Item&amp;gt;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items.forEach&amp;nbsp;{&amp;nbsp;item&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;onClick&amp;nbsp;=&amp;nbsp;remember(item.id)&amp;nbsp;{&amp;nbsp;{&amp;nbsp;doSomething(item)&amp;nbsp;}&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ItemRow(item&amp;nbsp;=&amp;nbsp;item,&amp;nbsp;onClick&amp;nbsp;=&amp;nbsp;onClick)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h3&gt;陷阱2：unstable 类导致无法跳过&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;❌&amp;nbsp;List&amp;lt;T&amp;gt;&amp;nbsp;被&amp;nbsp;Compose&amp;nbsp;认为是&amp;nbsp;unstable（因为它是&amp;nbsp;MutableList&amp;nbsp;的接口）
@Composable
fun&amp;nbsp;ItemList(items:&amp;nbsp;List&amp;lt;String&amp;gt;)&amp;nbsp;{&amp;nbsp;...&amp;nbsp;}

//&amp;nbsp;✅&amp;nbsp;方案1：使用&amp;nbsp;@Stable&amp;nbsp;或&amp;nbsp;@Immutable&amp;nbsp;注解包装
@Immutable
data&amp;nbsp;class&amp;nbsp;ImmutableList&amp;lt;T&amp;gt;(val&amp;nbsp;items:&amp;nbsp;List&amp;lt;T&amp;gt;)

//&amp;nbsp;✅&amp;nbsp;方案2：使用&amp;nbsp;kotlinx.collections.immutable
implementation(&amp;quot;org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7&amp;quot;)

@Composable
fun&amp;nbsp;ItemList(items:&amp;nbsp;ImmutableList&amp;lt;String&amp;gt;)&amp;nbsp;{&amp;nbsp;...&amp;nbsp;}&lt;/pre&gt;&lt;h3&gt;陷阱3：读取 State 的位置影响重组范围&lt;/h3&gt;&lt;p&gt;将 State 的读取尽可能下移到最小的 Composable 范围内，是减少重组范围的关键技巧。&lt;/p&gt;&lt;pre&gt;//&amp;nbsp;❌&amp;nbsp;在父级读取&amp;nbsp;State，导致整个父组件重组
@Composable
fun&amp;nbsp;Screen(viewModel:&amp;nbsp;MyViewModel)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;uiState&amp;nbsp;by&amp;nbsp;viewModel.uiState.collectAsState()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Column&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Header(title&amp;nbsp;=&amp;nbsp;uiState.title)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;只有这里需要&amp;nbsp;title
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Body(content&amp;nbsp;=&amp;nbsp;uiState.content)&amp;nbsp;&amp;nbsp;//&amp;nbsp;只有这里需要&amp;nbsp;content
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

//&amp;nbsp;✅&amp;nbsp;将&amp;nbsp;State&amp;nbsp;读取下移，各子组件独立重组
@Composable
fun&amp;nbsp;Screen(viewModel:&amp;nbsp;MyViewModel)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Column&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Header(titleFlow&amp;nbsp;=&amp;nbsp;viewModel.titleFlow)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Body(contentFlow&amp;nbsp;=&amp;nbsp;viewModel.contentFlow)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;三、使用 Compose 编译器报告分析重组&lt;/h2&gt;&lt;p&gt;光靠肉眼审查代码很低效，Compose 编译器提供了强大的报告工具，可以直接告诉你哪些 Composable 是 restartable、skippable 或 unstable 的。&lt;/p&gt;&lt;h3&gt;开启编译器报告&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;build.gradle.kts&amp;nbsp;(app&amp;nbsp;模块)
android&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;kotlinOptions&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;freeCompilerArgs&amp;nbsp;+=&amp;nbsp;listOf(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;-P&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_reports&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;freeCompilerArgs&amp;nbsp;+=&amp;nbsp;listOf(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;-P&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_metrics&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;p&gt;编译后在 &lt;code&gt;build/compose_reports/&lt;/code&gt; 目录下会生成报告文件，其中 &lt;code&gt;*-composables.txt&lt;/code&gt; 列出每个 Composable 的稳定性分析：&lt;/p&gt;&lt;pre&gt;restartable&amp;nbsp;skippable&amp;nbsp;scheme(&amp;quot;[0,&amp;nbsp;65536]&amp;quot;)&amp;nbsp;fun&amp;nbsp;UserCard(
&amp;nbsp;&amp;nbsp;stable&amp;nbsp;user:&amp;nbsp;User
)

restartable&amp;nbsp;scheme(&amp;quot;[0,&amp;nbsp;65536]&amp;quot;)&amp;nbsp;fun&amp;nbsp;OrderList(
&amp;nbsp;&amp;nbsp;unstable&amp;nbsp;orders:&amp;nbsp;List&amp;lt;Order&amp;gt;&amp;nbsp;&amp;nbsp;//&amp;nbsp;⚠️&amp;nbsp;这里！无法被跳过
)&lt;/pre&gt;&lt;h3&gt;使用 Layout Inspector 实时观测重组&lt;/h3&gt;&lt;p&gt;Android Studio 的 Layout Inspector 支持 Compose，可以实时高亮哪些 Composable 正在重组，并显示重组次数。开启路径：View → Tool Windows → Layout Inspector，选中 App Process 后勾选&amp;quot;Show Recomposition Counts&amp;quot;。&lt;/p&gt;&lt;h2&gt;四、LazyList 性能优化：避免常见的 100ms 卡顿&lt;/h2&gt;&lt;p&gt;LazyColumn / LazyRow 是 Compose 中最常用的列表组件，也是最容易踩坑的地方。&lt;/p&gt;&lt;h3&gt;1. key 参数：避免无效的 item 重组&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;❌&amp;nbsp;没有&amp;nbsp;key，数据变化时所有&amp;nbsp;item&amp;nbsp;都可能重组
LazyColumn&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items(items)&amp;nbsp;{&amp;nbsp;item&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ItemCard(item)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

//&amp;nbsp;✅&amp;nbsp;指定稳定的&amp;nbsp;key，Compose&amp;nbsp;只重组真正变化的&amp;nbsp;item
LazyColumn&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items(items,&amp;nbsp;key&amp;nbsp;=&amp;nbsp;{&amp;nbsp;it.id&amp;nbsp;})&amp;nbsp;{&amp;nbsp;item&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ItemCard(item)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h3&gt;2. contentType：加速 item 复用&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;当列表有多种类型时，指定&amp;nbsp;contentType&amp;nbsp;可以提高复用效率
LazyColumn&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items&amp;nbsp;=&amp;nbsp;feedItems,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;{&amp;nbsp;it.id&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contentType&amp;nbsp;=&amp;nbsp;{&amp;nbsp;it.type&amp;nbsp;}&amp;nbsp;//&amp;nbsp;&amp;quot;post&amp;quot;,&amp;nbsp;&amp;quot;ad&amp;quot;,&amp;nbsp;&amp;quot;story&amp;quot;&amp;nbsp;等
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{&amp;nbsp;item&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;when&amp;nbsp;(item.type)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;post&amp;quot;&amp;nbsp;-&amp;gt;&amp;nbsp;PostCard(item)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;ad&amp;quot;&amp;nbsp;-&amp;gt;&amp;nbsp;AdBanner(item)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;-&amp;gt;&amp;nbsp;StoryCard(item)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h3&gt;3. 预加载更多内容（prefetchDistance）&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;自定义&amp;nbsp;LazyListState&amp;nbsp;的预加载距离
val&amp;nbsp;state&amp;nbsp;=&amp;nbsp;rememberLazyListState()
val&amp;nbsp;prefetchState&amp;nbsp;=&amp;nbsp;rememberLazyListPrefetchState(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prefetchScheduler&amp;nbsp;=&amp;nbsp;AsyncPrefetchScheduler()
)
LazyColumn(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;state&amp;nbsp;=&amp;nbsp;state,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prefetchState&amp;nbsp;=&amp;nbsp;prefetchState
)&amp;nbsp;{&amp;nbsp;...&amp;nbsp;}&lt;/pre&gt;&lt;h3&gt;4. 避免在 LazyList 中嵌套滚动列表&lt;/h3&gt;&lt;p&gt;在 LazyColumn 中嵌套 LazyRow 时，内层 LazyRow 的高度必须固定，否则会导致无限高度测量异常：&lt;/p&gt;&lt;pre&gt;LazyColumn&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;item&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LazyRow(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier.height(120.dp)&amp;nbsp;//&amp;nbsp;✅&amp;nbsp;必须固定高度
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;items(horizontalItems)&amp;nbsp;{&amp;nbsp;ItemChip(it)&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;五、状态管理对性能的影响&lt;/h2&gt;&lt;p&gt;不合理的状态管理会让本可避免的重组频繁发生。&lt;/p&gt;&lt;h3&gt;优先选择细粒度 State 而非大对象&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;❌&amp;nbsp;一个大的&amp;nbsp;data&amp;nbsp;class&amp;nbsp;State，任何字段变化都触发全量重组
data&amp;nbsp;class&amp;nbsp;ScreenState(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;title:&amp;nbsp;String,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;isLoading:&amp;nbsp;Boolean,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;items:&amp;nbsp;List&amp;lt;Item&amp;gt;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;errorMsg:&amp;nbsp;String?
)
val&amp;nbsp;state&amp;nbsp;by&amp;nbsp;viewModel.screenState.collectAsState()

//&amp;nbsp;✅&amp;nbsp;拆分&amp;nbsp;State，按需收集
val&amp;nbsp;title&amp;nbsp;by&amp;nbsp;viewModel.title.collectAsState()
val&amp;nbsp;isLoading&amp;nbsp;by&amp;nbsp;viewModel.isLoading.collectAsState()
val&amp;nbsp;items&amp;nbsp;by&amp;nbsp;viewModel.items.collectAsState()&lt;/pre&gt;&lt;h3&gt;derivedStateOf：避免 State 衍生导致的过度重组&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;场景：根据列表滚动位置判断是否显示&amp;quot;回到顶部&amp;quot;按钮
val&amp;nbsp;listState&amp;nbsp;=&amp;nbsp;rememberLazyListState()

//&amp;nbsp;❌&amp;nbsp;每次滚动都会触发&amp;nbsp;showTopButton&amp;nbsp;的重组
val&amp;nbsp;showTopButton&amp;nbsp;=&amp;nbsp;listState.firstVisibleItemIndex&amp;nbsp;&amp;gt;&amp;nbsp;0

//&amp;nbsp;✅&amp;nbsp;只有&amp;nbsp;Boolean&amp;nbsp;值真正变化时才触发重组
val&amp;nbsp;showTopButton&amp;nbsp;by&amp;nbsp;remember&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;derivedStateOf&amp;nbsp;{&amp;nbsp;listState.firstVisibleItemIndex&amp;nbsp;&amp;gt;&amp;nbsp;0&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;六、图片加载与异步操作最佳实践&lt;/h2&gt;&lt;p&gt;图片加载和网络请求是 Android 应用中最常见的异步操作，处理不当会严重影响 Compose 性能。&lt;/p&gt;&lt;h3&gt;Coil 3 + AsyncImage 最佳实践&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;build.gradle.kts
implementation(&amp;quot;io.coil-kt.coil3:coil-compose:3.1.0&amp;quot;)
implementation(&amp;quot;io.coil-kt.coil3:coil-network-okhttp:3.1.0&amp;quot;)

//&amp;nbsp;使用方式（自动处理内存缓存、磁盘缓存）
AsyncImage(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;model&amp;nbsp;=&amp;nbsp;ImageRequest.Builder(LocalContext.current)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.data(imageUrl)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.crossfade(true)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.memoryCachePolicy(CachePolicy.ENABLED)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.diskCachePolicy(CachePolicy.ENABLED)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.build(),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contentDescription&amp;nbsp;=&amp;nbsp;&amp;quot;User&amp;nbsp;avatar&amp;quot;,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;contentScale&amp;nbsp;=&amp;nbsp;ContentScale.Crop,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;modifier&amp;nbsp;=&amp;nbsp;Modifier.size(48.dp).clip(CircleShape)
)&lt;/pre&gt;&lt;h3&gt;LaunchedEffect vs SideEffect vs DisposableEffect&lt;/h3&gt;&lt;pre&gt;//&amp;nbsp;LaunchedEffect：用于一次性或&amp;nbsp;key&amp;nbsp;变化时触发的挂起协程
LaunchedEffect(userId)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;viewModel.loadUserData(userId)&amp;nbsp;//&amp;nbsp;userId&amp;nbsp;变化时重新加载
}

//&amp;nbsp;SideEffect：每次重组都执行（用于同步&amp;nbsp;Compose&amp;nbsp;State&amp;nbsp;到非&amp;nbsp;Compose&amp;nbsp;系统）
SideEffect&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;analyticsTracker.setCurrentScreen(currentRoute)
}

//&amp;nbsp;DisposableEffect：需要清理资源时使用
DisposableEffect(lifecycleOwner)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;val&amp;nbsp;observer&amp;nbsp;=&amp;nbsp;LifecycleEventObserver&amp;nbsp;{&amp;nbsp;_,&amp;nbsp;event&amp;nbsp;-&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(event&amp;nbsp;==&amp;nbsp;Lifecycle.Event.ON_RESUME)&amp;nbsp;viewModel.refresh()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lifecycleOwner.lifecycle.addObserver(observer)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;onDispose&amp;nbsp;{&amp;nbsp;lifecycleOwner.lifecycle.removeObserver(observer)&amp;nbsp;}
}&lt;/pre&gt;&lt;h2&gt;七、实战 Checklist：Compose 性能优化清单&lt;/h2&gt;&lt;p&gt;以下是一份可直接应用到项目的性能优化 Checklist：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;开启编译器报告&lt;/strong&gt;，检查关键 Composable 是否为 skippable&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;所有 data class 参数&lt;/strong&gt;确保字段为 val（非 var），否则标注 @Stable/@Immutable&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;集合类型&lt;/strong&gt;（List/Map/Set）使用 kotlinx.collections.immutable 或自定义 @Immutable 包装&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;LazyList 的每个 items&lt;/strong&gt; 都指定了稳定的 key 和 contentType&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;滚动位置判断&lt;/strong&gt;统一改用 derivedStateOf 包裹&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;Lambda 参数&lt;/strong&gt;（onClick 等）在循环中用 remember(key) 缓存&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;State 读取&lt;/strong&gt;尽可能下移到最小的 Composable 范围&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;图片加载&lt;/strong&gt;使用 Coil3/Glide Compose，启用内存+磁盘缓存&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ 使用 &lt;strong&gt;Layout Inspector 的重组计数&lt;/strong&gt;功能，定位热点 Composable&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;使用 Macrobenchmark&lt;/strong&gt; 对关键页面做帧率基准测试&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Compose 性能优化是一个需要持续迭代的过程。建议在项目初期就养成良好习惯：每新增一个 Composable，就思考它的 stability 和 recomposition 范围。结合编译器报告和 Layout Inspector，大多数性能问题在开发阶段就能被发现和修复，而不是等到上线后才发现卡顿。&lt;/p&gt;</description><pubDate>Thu, 14 May 2026 08:08:40 +0800</pubDate></item><item><title>AI Agent 记忆管理实战：让你的智能体真正记住上下文</title><link>https://blog.resmic.cn/post/262.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260513080956177863099652297.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;&gt;&lt;/p&gt;

&lt;h2&gt;为什么 AI Agent 需要记忆管理？&lt;/h2&gt;
&lt;p&gt;大语言模型（LLM）本质上是无状态的——每次调用都是一次全新的对话，模型对之前发生的事情一无所知。对于简单的问答场景，这并不是问题；但当我们构建需要持续工作的 AI Agent 时，缺乏记忆会导致以下问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无法记住用户的个人偏好和历史操作&lt;/li&gt;
&lt;li&gt;每轮对话都要重复提供相同的背景信息&lt;/li&gt;
&lt;li&gt;多步骤任务执行中断后无法恢复&lt;/li&gt;
&lt;li&gt;长对话超出 Token 窗口后信息丢失&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，记忆管理成为构建生产级 AI Agent 的必备能力。业界通常将记忆分为四个层次：&lt;strong&gt;短期记忆（In-Context Memory）&lt;/strong&gt;、&lt;strong&gt;外部记忆（External Memory）&lt;/strong&gt;、&lt;strong&gt;情景记忆（Episodic Memory）&lt;/strong&gt;和&lt;strong&gt;语义记忆（Semantic Memory）&lt;/strong&gt;。&lt;/p&gt;

&lt;h2&gt;短期记忆：对话历史的管理策略&lt;/h2&gt;
&lt;p&gt;短期记忆是最直接的方案——把对话历史直接塞入 Prompt。但 LLM 的 Context Window 有限，随着对话增长，我们需要合理的截断和压缩策略。&lt;/p&gt;
&lt;p&gt;LangChain 提供了多种开箱即用的 Memory 组件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain.memory import (
    ConversationBufferMemory,
    ConversationSummaryMemory,
    ConversationBufferWindowMemory,
    ConversationTokenBufferMemory
)
from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(model=&quot;gpt-4o&quot;, temperature=0)

# 1. 滑动窗口记忆：只保留最近 K 轮对话
window_memory = ConversationBufferWindowMemory(k=5)

# 2. Token 限制记忆：按 Token 数控制记忆长度
token_memory = ConversationTokenBufferMemory(
    llm=llm,
    max_token_limit=2000
)

# 3. 摘要记忆：自动将旧对话压缩为摘要
summary_memory = ConversationSummaryMemory(llm=llm)

# 实战：使用摘要记忆构建持久对话
from langchain.chains import ConversationChain

chain = ConversationChain(llm=llm, memory=summary_memory, verbose=True)
response = chain.predict(input=&quot;我叫张伟，是一名 Python 后端工程师&quot;)
response = chain.predict(input=&quot;我最近在学习 AI Agent 开发&quot;)
response = chain.predict(input=&quot;你还记得我叫什么名字吗？&quot;)
print(response)  # 模型会正确回忆起&quot;张伟&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于实时性要求高的场景，推荐使用 &lt;strong&gt;ConversationTokenBufferMemory&lt;/strong&gt;，它能精确控制每次 API 调用的 Token 消耗；对于长时间对话，&lt;strong&gt;ConversationSummaryMemory&lt;/strong&gt; 通过动态摘要保留关键信息，是更优的选择。&lt;/p&gt;

&lt;h2&gt;长期记忆：向量数据库的引入&lt;/h2&gt;
&lt;p&gt;短期记忆无法跨会话持久化。要让 Agent 真正&quot;记住&quot;用户，需要引入外部存储。向量数据库是目前最主流的方案——将记忆内容嵌入为向量，通过语义相似度检索相关记忆。&lt;/p&gt;
&lt;p&gt;以下是基于 &lt;strong&gt;Chroma&lt;/strong&gt; 向量数据库实现长期记忆的完整示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.memory import VectorStoreRetrieverMemory
import chromadb

# 初始化持久化向量存储
persist_dir = &quot;./agent_memory_db&quot;
embeddings = OpenAIEmbeddings()

vectorstore = Chroma(
    collection_name=&quot;agent_long_term_memory&quot;,
    embedding_function=embeddings,
    persist_directory=persist_dir
)

# 创建基于向量检索的记忆
retriever = vectorstore.as_retriever(search_kwargs={&quot;k&quot;: 3})
memory = VectorStoreRetrieverMemory(retriever=retriever)

# 存储记忆片段
memory.save_context(
    {&quot;input&quot;: &quot;我最喜欢的编程语言是 Python&quot;},
    {&quot;output&quot;: &quot;已记录您偏好 Python&quot;}
)
memory.save_context(
    {&quot;input&quot;: &quot;我在北京工作，每天坐地铁上班&quot;},
    {&quot;output&quot;: &quot;已记录您在北京工作&quot;}
)
memory.save_context(
    {&quot;input&quot;: &quot;我有一只叫做「代码」的橘猫&quot;},
    {&quot;output&quot;: &quot;已记录您的宠物信息&quot;}
)

# 语义检索：查找与&quot;宠物&quot;相关的记忆
result = memory.load_memory_variables({&quot;prompt&quot;: &quot;告诉我关于你的猫&quot;})
print(result[&quot;history&quot;])
# 输出：Human: 我有一只叫做「代码」的橘猫
#        AI: 已记录您的宠物信息

# 持久化到磁盘
vectorstore.persist()
print(&quot;记忆已持久化，下次启动可直接加载&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;向量记忆的核心优势在于&lt;strong&gt;语义检索&lt;/strong&gt;——即使用户问的方式不同，系统也能找到最相关的历史记忆。这比简单的关键词匹配强大得多。&lt;/p&gt;

&lt;h2&gt;结构化记忆：用 JSON 存储用户画像&lt;/h2&gt;
&lt;p&gt;除了非结构化的对话记忆，很多场景需要维护结构化的用户状态，例如用户偏好、任务进度、个人档案等。推荐使用 JSON 文件或 Redis 存储，配合 Agent 的工具调用能力进行读写。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import json
import os
from datetime import datetime
from langchain.tools import tool
from langchain.agents import initialize_agent, AgentType
from langchain.chat_models import ChatOpenAI

USER_PROFILE_PATH = &quot;./user_profiles/{user_id}.json&quot;

def load_profile(user_id: str) -&gt; dict:
    path = USER_PROFILE_PATH.format(user_id=user_id)
    if os.path.exists(path):
        with open(path) as f:
            return json.load(f)
    return {&quot;user_id&quot;: user_id, &quot;preferences&quot;: {}, &quot;history&quot;: []}

def save_profile(user_id: str, profile: dict):
    path = USER_PROFILE_PATH.format(user_id=user_id)
    os.makedirs(os.path.dirname(path), exist_ok=True)
    with open(path, &quot;w&quot;) as f:
        json.dump(profile, f, ensure_ascii=False, indent=2)

@tool
def remember_user_preference(user_id: str, key: str, value: str) -&gt; str:
    &quot;&quot;&quot;记住用户的某个偏好或信息&quot;&quot;&quot;
    profile = load_profile(user_id)
    profile[&quot;preferences&quot;][key] = value
    profile[&quot;history&quot;].append({
        &quot;timestamp&quot;: datetime.now().isoformat(),
        &quot;action&quot;: f&quot;记录偏好: {key}={value}&quot;
    })
    save_profile(user_id, profile)
    return f&quot;已记住：{key} = {value}&quot;

@tool
def recall_user_info(user_id: str, query: str) -&gt; str:
    &quot;&quot;&quot;回忆用户的某个信息&quot;&quot;&quot;
    profile = load_profile(user_id)
    prefs = profile.get(&quot;preferences&quot;, {})
    if query in prefs:
        return f&quot;{query}: {prefs[query]}&quot;
    # 模糊匹配
    matches = {k: v for k, v in prefs.items() if query.lower() in k.lower()}
    return json.dumps(matches, ensure_ascii=False) if matches else &quot;未找到相关记忆&quot;

# 将工具绑定到 Agent
llm = ChatOpenAI(model=&quot;gpt-4o&quot;, temperature=0)
agent = initialize_agent(
    tools=[remember_user_preference, recall_user_info],
    llm=llm,
    agent=AgentType.OPENAI_FUNCTIONS,
    verbose=True
)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;记忆管理最佳实践与踩坑总结&lt;/h2&gt;
&lt;p&gt;经过实际项目的验证，以下是构建 AI Agent 记忆系统时的关键经验：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分层存储&lt;/strong&gt;：短期对话历史用 Token Buffer，中期用摘要压缩，长期用向量数据库——三层结合效果最佳&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;记忆隔离&lt;/strong&gt;：不同用户的记忆必须严格隔离，以 user_id 作为命名空间，避免信息泄露&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;遗忘机制&lt;/strong&gt;：实现 TTL（Time-To-Live）清理过期记忆，防止向量库无限膨胀&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检索调优&lt;/strong&gt;：向量检索的 top-k 值不宜过大（推荐 3-5），过多的记忆反而会引入噪声，降低回答质量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;记忆蒸馏&lt;/strong&gt;：定期用 LLM 对原始记忆进行摘要提炼，提取关键事实存入结构化存储，提升检索效率&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;冷启动问题&lt;/strong&gt;：新用户没有记忆时，提供通用的 persona prompt 作为默认上下文&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;随着 &lt;strong&gt;LangGraph&lt;/strong&gt;、&lt;strong&gt;AutoGen&lt;/strong&gt; 等多 Agent 框架的成熟，记忆管理正在向更复杂的方向演进——多 Agent 共享记忆池、跨模态记忆（图文混合）、主动记忆整合等都是值得关注的前沿方向。&lt;/p&gt;
&lt;p&gt;建议将记忆管理能力封装为独立的微服务，通过 REST API 向多个 Agent 提供统一的记忆读写接口，这样既便于维护，又能在不同 Agent 之间共享用户上下文。&lt;/p&gt;
</description><pubDate>Wed, 13 May 2026 08:13:32 +0800</pubDate></item><item><title>Jetpack Compose 性能优化实战：告别卡顿的8个核心技巧</title><link>https://blog.resmic.cn/post/261.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260512080625177854438569019.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;&gt;&lt;/p&gt;

&lt;h2&gt;一、为什么 Jetpack Compose 性能优化如此重要&lt;/h2&gt;
&lt;p&gt;Jetpack Compose 自 2021 年正式发布以来，已经成为 Android UI 开发的官方推荐方案。与传统 View 系统相比，Compose 的声明式编程模型让 UI 代码更简洁、更易维护。然而，声明式 UI 框架有一个天然挑战：&lt;strong&gt;不当的写法会导致大量不必要的重组（Recomposition）&lt;/strong&gt;，严重影响应用流畅度。&lt;/p&gt;
&lt;p&gt;在实际项目中，开发者常常遇到以下问题：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;列表滑动时掉帧，FPS 低于 60&lt;/li&gt;
  &lt;li&gt;状态更新触发了整个页面的重组&lt;/li&gt;
  &lt;li&gt;动画卡顿，交互响应迟钝&lt;/li&gt;
  &lt;li&gt;内存占用随使用时间持续增长&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文将系统介绍 Jetpack Compose 性能优化的核心方法，结合实际代码示例，帮助你打造丝滑流畅的 Android 应用。&lt;/p&gt;

&lt;h2&gt;二、深入理解重组机制&lt;/h2&gt;
&lt;p&gt;理解 Compose 的重组机制是性能优化的基础。Compose 运行时会追踪每个 Composable 函数所读取的 State，当 State 发生变化时，只重组读取了该 State 的函数。但如果使用不当，依然会导致不必要的重组。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;重组的基本规则：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Composable 函数的参数类型必须是稳定（Stable）类型，才能被 Compose 编译器优化跳过&lt;/li&gt;
  &lt;li&gt;不稳定的类型（如普通 class、List、Map）每次都会触发重组&lt;/li&gt;
  &lt;li&gt;Lambda 函数如果在组合外部定义，可能导致引用不稳定&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 &lt;code&gt;@Stable&lt;/code&gt; 和 &lt;code&gt;@Immutable&lt;/code&gt; 注解可以帮助编译器识别稳定类型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 不稳定的数据类（普通 data class）
data class User(val name: String, val age: Int)

// 标记为稳定，告知 Compose 编译器参数不会意外变化
@Stable
data class User(val name: String, val age: Int)

// 完全不可变的数据类，重组跳过条件最宽松
@Immutable
data class UserProfile(val id: Long, val name: String, val avatarUrl: String)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;三、remember 与 derivedStateOf 的正确使用&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;remember&lt;/code&gt; 是 Compose 中缓存计算结果的核心 API，但错误使用会带来性能问题。&lt;code&gt;derivedStateOf&lt;/code&gt; 则用于从其他 State 派生出新的 State，避免不必要的重组。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;remember 的常见误区：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ❌ 错误：每次重组都创建新对象
@Composable
fun BadExample(items: List&amp;lt;String&amp;gt;) {
    val filteredItems = items.filter { it.isNotEmpty() } // 每次重组都重新计算
    LazyColumn {
        items(filteredItems) { item -&gt;
            Text(item)
        }
    }
}

// ✅ 正确：用 remember 缓存计算结果
@Composable
fun GoodExample(items: List&amp;lt;String&amp;gt;) {
    val filteredItems = remember(items) {
        items.filter { it.isNotEmpty() }
    }
    LazyColumn {
        items(filteredItems) { item -&gt;
            Text(item)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;derivedStateOf 的使用场景：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 场景：列表滚动时，只在第一项不可见时才显示&quot;回到顶部&quot;按钮
@Composable
fun ScrollableList() {
    val listState = rememberLazyListState()
    
    // ✅ 使用 derivedStateOf，避免每次滚动都触发重组
    val showScrollToTop by remember {
        derivedStateOf { listState.firstVisibleItemIndex &gt; 0 }
    }
    
    Box {
        LazyColumn(state = listState) {
            items(100) { index -&gt;
                ListItem(index)
            }
        }
        if (showScrollToTop) {
            FloatingActionButton(
                onClick = { /* scroll to top */ },
                modifier = Modifier.align(Alignment.BottomEnd)
            ) {
                Icon(Icons.Default.KeyboardArrowUp, contentDescription = &quot;回到顶部&quot;)
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;四、LazyList 性能调优实战&lt;/h2&gt;
&lt;p&gt;LazyColumn 和 LazyRow 是 Compose 中最常用的列表组件，也是性能问题的高发区。以下是关键优化技巧：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 提供稳定的 key&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ❌ 没有 key，Compose 无法识别 item 是否变化，全量重组
LazyColumn {
    items(users) { user -&gt;
        UserCard(user)
    }
}

// ✅ 提供稳定 key，只重组真正变化的 item
LazyColumn {
    items(users, key = { user -&gt; user.id }) { user -&gt;
        UserCard(user)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. 使用 contentType 优化不同类型 item 的复用&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sealed class FeedItem {
    data class Post(val content: String) : FeedItem()
    data class Ad(val imageUrl: String) : FeedItem()
}

LazyColumn {
    items(
        feedItems,
        key = { it.hashCode() },
        contentType = { item -&gt;
            when (item) {
                is FeedItem.Post -&gt; &quot;post&quot;
                is FeedItem.Ad -&gt; &quot;ad&quot;
            }
        }
    ) { item -&gt;
        when (item) {
            is FeedItem.Post -&gt; PostCard(item)
            is FeedItem.Ad -&gt; AdCard(item)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. 避免在 item lambda 中进行复杂计算&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ❌ 在 item lambda 中进行重度计算
LazyColumn {
    items(articles) { article -&gt;
        val processedContent = article.body
            .replace(Regex(&quot;\\s+&quot;), &quot; &quot;)
            .take(200) // 每次重组都执行
        ArticlePreview(processedContent)
    }
}

// ✅ 数据预处理移到 ViewModel 或 remember
val processedArticles = remember(articles) {
    articles.map { article -&gt;
        article.copy(body = article.body.replace(Regex(&quot;\\s+&quot;), &quot; &quot;).take(200))
    }
}
LazyColumn {
    items(processedArticles, key = { it.id }) { article -&gt;
        ArticlePreview(article.body)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;五、状态管理最佳实践&lt;/h2&gt;
&lt;p&gt;状态管理是 Compose 性能优化中最核心的话题。状态提升（State Hoisting）的位置直接影响重组范围。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;状态下沉原则：状态应该尽量放在离使用它的 Composable 最近的位置&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ❌ 状态提升过高，导致父组件不必要的重组
@Composable
fun ParentScreen() {
    var isExpanded by remember { mutableStateOf(false) }
    var selectedTab by remember { mutableStateOf(0) }
    
    Column {
        HeavyComponent() // isExpanded 变化时，这个组件也被重组
        ExpandableCard(isExpanded, onToggle = { isExpanded = !isExpanded })
        TabRow(selectedTab, onTabSelected = { selectedTab = it })
    }
}

// ✅ 将状态下沉到需要的组件内部
@Composable
fun ExpandableCard() {
    var isExpanded by remember { mutableStateOf(false) } // 状态内聚
    // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;使用 ViewModel 管理复杂状态，避免重复创建：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ViewModel 状态定义（推荐使用 StateFlow）
class ArticleViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(ArticleUiState())
    val uiState: StateFlow&amp;lt;ArticleUiState&amp;gt; = _uiState.asStateFlow()
    
    fun loadArticles() {
        viewModelScope.launch {
            repository.getArticles().collect { articles -&gt;
                _uiState.update { it.copy(articles = articles, isLoading = false) }
            }
        }
    }
}

// Composable 中收集状态
@Composable
fun ArticleScreen(viewModel: ArticleViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    
    when {
        uiState.isLoading -&gt; LoadingIndicator()
        uiState.articles.isEmpty() -&gt; EmptyState()
        else -&gt; ArticleList(uiState.articles)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;六、使用 Compose 编译器指标分析性能瓶颈&lt;/h2&gt;
&lt;p&gt;Compose 编译器可以生成详细的指标报告，帮助我们找到不稳定的 Composable 和参数类型。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在 build.gradle 中开启编译器指标：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// app/build.gradle.kts
android {
    kotlinOptions {
        freeCompilerArgs += listOf(
            &quot;-P&quot;,
            &quot;plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_metrics&quot;,
            &quot;-P&quot;,
            &quot;plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_metrics&quot;
        )
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建后，在 &lt;code&gt;build/compose_metrics/&lt;/code&gt; 目录下会生成以下报告：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;*-composables.txt&lt;/code&gt;：每个 Composable 的重组信息&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;*-classes.txt&lt;/code&gt;：类的稳定性分析&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;*-composables.csv&lt;/code&gt;：可导入 Excel 分析的 CSV 格式报告&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;读取报告示例：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// composables.txt 中的典型输出
restartable skippable scheme(&quot;[androidx.compose.ui.UiComposable]&quot;) fun UserCard(
  stable user: User  // ✅ 参数稳定，可跳过
)

restartable scheme(&quot;[androidx.compose.ui.UiComposable]&quot;) fun FeedItem(
  unstable item: FeedData  // ❌ 参数不稳定，无法跳过重组
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于标记为 &lt;code&gt;unstable&lt;/code&gt; 的类型，解决方案是：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;添加 &lt;code&gt;@Immutable&lt;/code&gt; 或 &lt;code&gt;@Stable&lt;/code&gt; 注解&lt;/li&gt;
  &lt;li&gt;将 &lt;code&gt;List&lt;/code&gt; 替换为 &lt;code&gt;ImmutableList&lt;/code&gt;（来自 kotlinx.collections.immutable 库）&lt;/li&gt;
  &lt;li&gt;将数据类改为只包含稳定类型的属性&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;七、实战：使用 Layout Inspector 定位重组热点&lt;/h2&gt;
&lt;p&gt;Android Studio 的 Layout Inspector 提供了实时的重组计数功能，是定位性能问题最直观的工具。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用步骤：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;连接真机或模拟器，运行 Debug 包&lt;/li&gt;
  &lt;li&gt;打开 &lt;strong&gt;View → Tool Windows → Layout Inspector&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;勾选 &lt;strong&gt;Show Recomposition Counts&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;操作应用，观察各 Composable 旁边的重组计数&lt;/li&gt;
  &lt;li&gt;重组次数异常高的组件就是优化目标&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;常见的重组热点及修复方案：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 问题：在父组件传递 onClick lambda 导致子组件重组
@Composable
fun ParentList(viewModel: MyViewModel) {
    val items by viewModel.items.collectAsState()
    
    // ❌ 每次 ParentList 重组，lambda 引用变化，子组件全部重组
    LazyColumn {
        items(items) { item -&gt;
            ItemCard(
                item = item,
                onClick = { viewModel.onItemClick(item.id) } // 新 lambda 引用
            )
        }
    }
}

// ✅ 使用 rememberUpdatedState 或将回调移入 ViewModel
@Composable
fun ParentList(viewModel: MyViewModel) {
    val items by viewModel.items.collectAsState()
    val onItemClick = remember { { id: Long -&gt; viewModel.onItemClick(id) } }
    
    LazyColumn {
        items(items, key = { it.id }) { item -&gt;
            ItemCard(
                item = item,
                onClick = { onItemClick(item.id) }
            )
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;八、总结与性能优化检查清单&lt;/h2&gt;
&lt;p&gt;经过以上各章节的深入讲解，我们可以总结出 Jetpack Compose 性能优化的核心要点：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;✅ 为数据类添加 &lt;code&gt;@Stable&lt;/code&gt;/&lt;code&gt;@Immutable&lt;/code&gt; 注解，确保参数稳定性&lt;/li&gt;
  &lt;li&gt;✅ 正确使用 &lt;code&gt;remember(key)&lt;/code&gt; 缓存计算结果，避免重复计算&lt;/li&gt;
  &lt;li&gt;✅ 用 &lt;code&gt;derivedStateOf&lt;/code&gt; 替代频繁读取的派生状态&lt;/li&gt;
  &lt;li&gt;✅ LazyList 必须提供稳定的 &lt;code&gt;key&lt;/code&gt;，不同类型 item 提供 &lt;code&gt;contentType&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;✅ 状态尽量内聚，避免不必要的状态提升导致大范围重组&lt;/li&gt;
  &lt;li&gt;✅ 开启编译器指标，定期检查不稳定的 Composable&lt;/li&gt;
  &lt;li&gt;✅ 使用 Layout Inspector 的重组计数功能定位热点&lt;/li&gt;
  &lt;li&gt;✅ 用 &lt;code&gt;ImmutableList&lt;/code&gt; 替代普通 &lt;code&gt;List&lt;/code&gt; 作为 Composable 参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;性能优化是一个持续的过程，建议在每个迭代周期中都进行性能基准测试，及时发现和修复重组问题。掌握这些技巧，你将能够构建出真正流畅的 Compose 应用，为用户带来卓越的体验。&lt;/p&gt;
</description><pubDate>Tue, 12 May 2026 08:11:24 +0800</pubDate></item><item><title>Vibe Coding 实战指南：用 AI 辅助编程实现 10 倍开发效率</title><link>https://blog.resmic.cn/post/260.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260511080804177845808425676.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;什么是 Vibe Coding？&lt;/h2&gt;&lt;p&gt;2025 年初，OpenAI 创始人 Andrej Karpathy 提出了 &lt;strong&gt;Vibe Coding&lt;/strong&gt; 这一概念，迅速在开发者社区引发热烈讨论。其核心思想是：开发者不再逐行编写代码，而是用自然语言描述想要实现的功能，由 AI 负责生成、调试、重构代码，开发者只需审查和验收结果。&lt;/p&gt;&lt;p&gt;这一范式的转变意义深远。传统开发中，程序员需要同时关注业务逻辑与实现细节；而在 Vibe Coding 中，AI 承担了大量的&amp;quot;体力劳动&amp;quot;，开发者的注意力可以完全集中在&lt;em&gt;「我想要什么」&lt;/em&gt;而非&lt;em&gt;「如何实现」&lt;/em&gt;。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;意图驱动：&lt;/strong&gt;用自然语言表达需求，AI 自动转化为可执行代码&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;快速迭代：&lt;/strong&gt;几秒内生成初稿，几分钟内完成功能闭环&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;降低门槛：&lt;/strong&gt;非专业开发者也能构建可用的软件原型&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;专注创造：&lt;/strong&gt;将重复性、样板式代码的编写全部交给 AI&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;主流 Vibe Coding 工具横评&lt;/h2&gt;&lt;p&gt;目前市场上已涌现出多款成熟的 Vibe Coding 工具，各有侧重：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cursor：&lt;/strong&gt;基于 VS Code 的 AI 编辑器，支持多文件上下文感知，Composer 模式可一键重构整个项目。适合有一定代码基础的开发者。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Windsurf（Codeium）：&lt;/strong&gt;主打&amp;quot;Flow&amp;quot;模式，AI 能自主规划任务、创建文件、运行命令，端到端完成功能开发。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;GitHub Copilot Workspace：&lt;/strong&gt;从 Issue 到 PR 的全流程自动化，深度集成 GitHub 生态，适合团队协作场景。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bolt.new / Lovable：&lt;/strong&gt;面向前端和全栈应用的 Web 端 AI 编程平台，零配置即可生成并部署完整 Web 应用。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Claude Code / Gemini CLI：&lt;/strong&gt;终端原生 AI 编程助手，适合喜欢命令行工作流的开发者。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Vibe Coding 实战技巧&lt;/h2&gt;&lt;p&gt;工具只是手段，真正决定 Vibe Coding 效果的是你与 AI 的&amp;quot;沟通质量&amp;quot;。以下是经过大量实践总结的核心技巧：&lt;/p&gt;&lt;h3&gt;1. 写好 Prompt 是第一生产力&lt;/h3&gt;&lt;p&gt;模糊的需求会产生模糊的代码。好的 Prompt 应包含：&lt;em&gt;目标功能、技术栈、约束条件、预期输出格式&lt;/em&gt;。&lt;/p&gt;&lt;pre&gt;#&amp;nbsp;❌&amp;nbsp;差的&amp;nbsp;Prompt
帮我做一个登录页面

#&amp;nbsp;✅&amp;nbsp;好的&amp;nbsp;Prompt
用&amp;nbsp;React&amp;nbsp;+&amp;nbsp;TypeScript&amp;nbsp;+&amp;nbsp;Tailwind&amp;nbsp;CSS&amp;nbsp;实现一个登录页面：
-&amp;nbsp;包含邮箱和密码输入框，带表单校验
-&amp;nbsp;登录按钮点击后调用&amp;nbsp;POST&amp;nbsp;/api/auth/login&amp;nbsp;接口
-&amp;nbsp;登录成功跳转到&amp;nbsp;/dashboard，失败显示错误提示
-&amp;nbsp;界面风格参考&amp;nbsp;Linear，暗色主题&lt;/pre&gt;&lt;h3&gt;2. 分治原则：大任务拆小步&lt;/h3&gt;&lt;p&gt;不要试图一次性生成整个应用。将大功能拆分为独立模块，逐步迭代，每次只让 AI 专注一个明确的子任务，成功率和质量都会大幅提升。&lt;/p&gt;&lt;pre&gt;#&amp;nbsp;推荐的任务拆分方式
Step&amp;nbsp;1:&amp;nbsp;生成数据库&amp;nbsp;Schema&amp;nbsp;和&amp;nbsp;Model&amp;nbsp;层
Step&amp;nbsp;2:&amp;nbsp;生成&amp;nbsp;API&amp;nbsp;路由和&amp;nbsp;Controller
Step&amp;nbsp;3:&amp;nbsp;生成前端组件
Step&amp;nbsp;4:&amp;nbsp;生成单元测试
Step&amp;nbsp;5:&amp;nbsp;整合联调&lt;/pre&gt;&lt;h3&gt;3. 善用上下文文件（Rules / AGENTS.md）&lt;/h3&gt;&lt;p&gt;大多数 AI 编辑器支持项目级规则文件（如 Cursor 的 &lt;code&gt;.cursorrules&lt;/code&gt;，Windsurf 的 &lt;code&gt;.windsurfrules&lt;/code&gt;）。在其中定义：技术栈偏好、代码规范、禁止模式、项目架构说明，能让 AI 在整个项目中保持一致的编码风格。&lt;/p&gt;&lt;h2&gt;Vibe Coding 的边界与风险&lt;/h2&gt;&lt;p&gt;Vibe Coding 并不是万能的，清醒认识其局限性同样重要：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;安全隐患：&lt;/strong&gt;AI 生成的代码可能包含 SQL 注入、XSS、不安全的依赖等漏洞，务必进行安全审查&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;技术债务：&lt;/strong&gt;快速生成的代码往往缺乏一致的架构，长期积累会造成维护困难&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;幻觉问题：&lt;/strong&gt;AI 可能生成看似正确实则有 bug 的代码，核心逻辑必须人工审查&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;过度依赖：&lt;/strong&gt;完全依赖 AI 会导致开发者丧失基础编程能力，不利于职业发展&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;最佳实践是把 Vibe Coding 定位为&lt;strong&gt;加速器而非替代品&lt;/strong&gt;——它处理重复劳动，你负责架构决策、业务逻辑设计和质量把关。&lt;/p&gt;&lt;h2&gt;展望：AI 原生开发工作流&lt;/h2&gt;&lt;p&gt;Vibe Coding 只是开始。随着多模态 AI 和 Agent 技术的成熟，软件开发工作流正在发生根本性重构：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;需求文档 → 代码的自动化将越来越完整&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;AI Agent 将能够独立完成端到端的功能开发和部署&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;人类开发者的角色将向&amp;quot;AI 产品经理 + 架构师&amp;quot;演进&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;软件开发的门槛将持续降低，创造力将成为核心竞争力&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;现在正是拥抱 Vibe Coding 的最佳时机。选一个趁手的工具，从你下一个功能开始实践，亲身感受 AI 时代的开发效率革命。&lt;/p&gt;</description><pubDate>Mon, 11 May 2026 08:08:19 +0800</pubDate></item><item><title>PHP 8.4 新特性全解析：属性钩子、非对称可见性与懒加载实战</title><link>https://blog.resmic.cn/post/259.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260510080644177837160422934.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;一、PHP 8.4 概览：为什么值得关注&lt;/h2&gt;&lt;p&gt;PHP 8.4 于 2024 年 11 月 21 日正式发布，这是 PHP 8.x 系列的最新里程碑版本。相较于 8.3，此次更新不仅修复了大量 Bug，更带来了多项影响深远的语言特性改进，进一步拉近了 PHP 与现代编程语言的距离。&lt;/p&gt;&lt;p&gt;对于日常业务开发者而言，PHP 8.4 带来的变化涉及类属性、可见性控制、数组操作、懒加载对象等多个维度，每一项都有实际的工程价值。本文将逐一拆解，配合代码示例，让你快速上手。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;属性钩子（Property Hooks）—— 告别繁琐的 getter/setter&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;非对称可见性（Asymmetric Visibility）—— 精细控制读写权限&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;链式 new 表达式不再需要括号包裹&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;新增数组查找函数 array_find / array_find_key&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;懒加载对象（Lazy Objects）原生支持&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;二、属性钩子（Property Hooks）深度解析&lt;/h2&gt;&lt;p&gt;属性钩子是 PHP 8.4 最受瞩目的特性之一，它允许在属性的 get 和 set 操作上附加自定义逻辑，无需再为每个属性手写 &lt;code&gt;getXxx()&lt;/code&gt; 和 &lt;code&gt;setXxx()&lt;/code&gt; 方法。&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

class&amp;nbsp;User&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;string&amp;nbsp;$name&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;get&amp;nbsp;=&amp;gt;&amp;nbsp;strtoupper($this-&amp;gt;name);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set(string&amp;nbsp;$value)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(strlen($value)&amp;nbsp;&amp;lt;&amp;nbsp;2)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw&amp;nbsp;new&amp;nbsp;\ValueError(&amp;#39;Name&amp;nbsp;must&amp;nbsp;be&amp;nbsp;at&amp;nbsp;least&amp;nbsp;2&amp;nbsp;characters.&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;name&amp;nbsp;=&amp;nbsp;$value;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(string&amp;nbsp;$name)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;name&amp;nbsp;=&amp;nbsp;$name;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$user&amp;nbsp;=&amp;nbsp;new&amp;nbsp;User(&amp;#39;alice&amp;#39;);
echo&amp;nbsp;$user-&amp;gt;name;&amp;nbsp;//&amp;nbsp;输出:&amp;nbsp;ALICE

$user-&amp;gt;name&amp;nbsp;=&amp;nbsp;&amp;#39;a&amp;#39;;&amp;nbsp;//&amp;nbsp;抛出&amp;nbsp;ValueError&lt;/pre&gt;&lt;p&gt;通过属性钩子，我们可以在保持属性访问语法简洁的同时，内嵌验证和转换逻辑。这对于领域驱动设计（DDD）中的值对象尤为适用。&lt;/p&gt;&lt;p&gt;钩子支持以下几种组合：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;只定义 &lt;code&gt;get&lt;/code&gt;：属性变为只读计算属性&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;只定义 &lt;code&gt;set&lt;/code&gt;：写入时触发验证/转换，读取按默认行为&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;同时定义 &lt;code&gt;get&lt;/code&gt; 和 &lt;code&gt;set&lt;/code&gt;：完整拦截读写&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;三、非对称可见性（Asymmetric Visibility）&lt;/h2&gt;&lt;p&gt;PHP 8.4 引入了非对称可见性语法，允许你对同一个属性分别指定读取可见性和写入可见性：&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

class&amp;nbsp;Order&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;private(set)&amp;nbsp;int&amp;nbsp;$id;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;protected(set)&amp;nbsp;string&amp;nbsp;$status&amp;nbsp;=&amp;nbsp;&amp;#39;pending&amp;#39;;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct(int&amp;nbsp;$id)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;id&amp;nbsp;=&amp;nbsp;$id;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;confirm():&amp;nbsp;void&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;status&amp;nbsp;=&amp;nbsp;&amp;#39;confirmed&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$order&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Order(1001);
echo&amp;nbsp;$order-&amp;gt;id;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;公开可读
echo&amp;nbsp;$order-&amp;gt;status;&amp;nbsp;//&amp;nbsp;公开可读

$order-&amp;gt;id&amp;nbsp;=&amp;nbsp;9999;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;Fatal&amp;nbsp;Error：外部无法写入&lt;/pre&gt;&lt;p&gt;这一特性让不可变值对象的构建变得更加自然，不再需要用 &lt;code&gt;readonly&lt;/code&gt; 限制整个生命周期，而是精确地控制谁能修改属性。&lt;/p&gt;&lt;p&gt;常见用途：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;public private(set)&lt;/code&gt;：外部只读，类内可写&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;public protected(set)&lt;/code&gt;：外部只读，子类可写&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;与属性钩子组合使用，构建健壮的值对象&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;四、新数组函数：array_find / array_find_key / array_any / array_all&lt;/h2&gt;&lt;p&gt;PHP 8.4 新增了四个语义清晰的数组操作函数，填补了长期以来需要用 &lt;code&gt;array_filter&lt;/code&gt; + &lt;code&gt;reset&lt;/code&gt; 组合绕路的空白：&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

$products&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;iPhone&amp;#39;,&amp;nbsp;&amp;#39;price&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;6999],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;Pixel&amp;#39;,&amp;nbsp;&amp;nbsp;&amp;#39;price&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;4999],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;Galaxy&amp;#39;,&amp;nbsp;&amp;#39;price&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;5999],
];

//&amp;nbsp;找到第一个价格超过&amp;nbsp;5000&amp;nbsp;的商品
$found&amp;nbsp;=&amp;nbsp;array_find($products,&amp;nbsp;fn($p)&amp;nbsp;=&amp;gt;&amp;nbsp;$p[&amp;#39;price&amp;#39;]&amp;nbsp;&amp;gt;&amp;nbsp;5000);
var_dump($found);&amp;nbsp;//&amp;nbsp;[&amp;#39;name&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;#39;iPhone&amp;#39;,&amp;nbsp;&amp;#39;price&amp;#39;&amp;nbsp;=&amp;gt;&amp;nbsp;6999]

//&amp;nbsp;找到对应的键
$key&amp;nbsp;=&amp;nbsp;array_find_key($products,&amp;nbsp;fn($p)&amp;nbsp;=&amp;gt;&amp;nbsp;$p[&amp;#39;price&amp;#39;]&amp;nbsp;&amp;gt;&amp;nbsp;5000);
var_dump($key);&amp;nbsp;//&amp;nbsp;int(0)

//&amp;nbsp;是否存在任一满足条件的元素
$anyExpensive&amp;nbsp;=&amp;nbsp;array_any($products,&amp;nbsp;fn($p)&amp;nbsp;=&amp;gt;&amp;nbsp;$p[&amp;#39;price&amp;#39;]&amp;nbsp;&amp;gt;&amp;nbsp;6000);
var_dump($anyExpensive);&amp;nbsp;//&amp;nbsp;bool(true)

//&amp;nbsp;是否所有元素都满足条件
$allExpensive&amp;nbsp;=&amp;nbsp;array_all($products,&amp;nbsp;fn($p)&amp;nbsp;=&amp;gt;&amp;nbsp;$p[&amp;#39;price&amp;#39;]&amp;nbsp;&amp;gt;&amp;nbsp;3000);
var_dump($allExpensive);&amp;nbsp;//&amp;nbsp;bool(true)&lt;/pre&gt;&lt;p&gt;这四个函数让数组查询代码更加语义化、可读性更强，在日常 CRUD 业务逻辑中会频繁用到。&lt;/p&gt;&lt;h2&gt;五、懒加载对象（Lazy Objects）与升级建议&lt;/h2&gt;&lt;p&gt;PHP 8.4 在反射 API 中原生支持懒加载对象（Lazy Objects），这是一项对框架开发者极为重要的底层能力。懒加载对象在被真正访问之前不会执行初始化逻辑，非常适合用于依赖注入容器中的代理对象实现。&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

class&amp;nbsp;HeavyService&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;__construct()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;模拟耗时初始化（如数据库连接）
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sleep(1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;HeavyService&amp;nbsp;initialized\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;doWork():&amp;nbsp;string&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;quot;Working!&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$reflector&amp;nbsp;=&amp;nbsp;new&amp;nbsp;ReflectionClass(HeavyService::class);

//&amp;nbsp;创建懒加载实例（此时不执行构造函数）
$lazy&amp;nbsp;=&amp;nbsp;$reflector-&amp;gt;newLazyGhost(function&amp;nbsp;(HeavyService&amp;nbsp;$obj)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$obj-&amp;gt;__construct();
});

echo&amp;nbsp;&amp;quot;Lazy&amp;nbsp;object&amp;nbsp;created&amp;nbsp;(no&amp;nbsp;init&amp;nbsp;yet)\n&amp;quot;;

//&amp;nbsp;真正访问时才初始化
echo&amp;nbsp;$lazy-&amp;gt;doWork();&amp;nbsp;//&amp;nbsp;输出:&amp;nbsp;HeavyService&amp;nbsp;initialized\nWorking!&lt;/pre&gt;&lt;p&gt;升级到 PHP 8.4 的建议：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;使用 &lt;code&gt;php -v&lt;/code&gt; 或 Docker 镜像 &lt;code&gt;php:8.4-fpm&lt;/code&gt; 快速体验新特性&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;运行 &lt;code&gt;composer require --dev phpstan/phpstan&lt;/code&gt; 借助静态分析确保兼容性&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;注意 PHP 8.4 废弃了 &lt;code&gt;implicitly nullable&lt;/code&gt; 参数语法，需将 &lt;code&gt;function foo(string $a = null)&lt;/code&gt; 改为 &lt;code&gt;function foo(?string $a = null)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;参考官方迁移指南：&lt;a href=&quot;https://www.php.net/manual/en/migration84.php&quot; target=&quot;_blank&quot;&gt;php.net/manual/en/migration84.php&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;PHP 8.4 在语言表达力和工程实践上都迈出了重要一步。无论是构建新项目还是维护遗留系统，了解这些新特性都将使你的 PHP 代码更简洁、更健壮。&lt;/p&gt;</description><pubDate>Sun, 10 May 2026 08:14:55 +0800</pubDate></item><item><title>PHP 8.4 新特性全解析：属性钩子、非对称可见性与懒对象实战指南</title><link>https://blog.resmic.cn/post/258.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260509080605177828516574229.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;&gt;&lt;/p&gt;

&lt;h2&gt;一、PHP 8.4 概览：为什么这次升级值得关注&lt;/h2&gt;
&lt;p&gt;PHP 8.4 于 2024 年 11 月正式发布，这是 PHP 8.x 系列中迄今为止改动最大、最具前瞻性的一次版本。它不仅延续了 PHP 8.0 以来的性能优化路线，更在语言层面引入了多项开发者期待已久的特性，让 PHP 在与 Python、Kotlin 等现代语言的竞争中更具吸引力。&lt;/p&gt;
&lt;p&gt;本文将从实际开发场景出发，逐一讲解 PHP 8.4 的核心新特性，每个特性都配有可运行的代码示例，帮助你快速上手并应用到真实项目中。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;属性钩子（Property Hooks）：OOP 的重大变革&lt;/li&gt;
  &lt;li&gt;非对称可见性（Asymmetric Visibility）：更精细的访问控制&lt;/li&gt;
  &lt;li&gt;全新数组函数：array_find、array_find_key 等&lt;/li&gt;
  &lt;li&gt;懒对象（Lazy Objects）：性能优化利器&lt;/li&gt;
  &lt;li&gt;HTML5 解析器：告别 libxml 的烦恼&lt;/li&gt;
  &lt;li&gt;其他改进：PDO、BCMath、JIT 增强&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;二、属性钩子（Property Hooks）：颠覆传统 Getter/Setter&lt;/h2&gt;
&lt;p&gt;这是 PHP 8.4 最受瞩目的特性之一。过去我们需要为每个属性手写 &lt;code&gt;getXxx()&lt;/code&gt; 和 &lt;code&gt;setXxx()&lt;/code&gt; 方法，代码冗余且维护成本高。属性钩子让属性本身拥有 &lt;code&gt;get&lt;/code&gt; 和 &lt;code&gt;set&lt;/code&gt; 逻辑，代码更简洁优雅。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

class User {
    public string $firstName;
    public string $lastName;

    // 虚拟属性：fullName 由 get 钩子动态计算
    public string $fullName {
        get =&amp;gt; $this-&amp;gt;firstName . ' ' . $this-&amp;gt;lastName;
        set {
            [$this-&amp;gt;firstName, $this-&amp;gt;lastName] = explode(' ', $value, 2);
        }
    }

    // 带验证的 set 钩子
    public int $age {
        set(int $value) {
            if ($value &amp;lt; 0 || $value &amp;gt; 150) {
                throw new \ValueError(&quot;Invalid age: $value&quot;);
            }
            $this-&amp;gt;age = $value;
        }
    }
}

$user = new User();
$user-&gt;fullName = 'Zhang Wei';
echo $user-&gt;firstName; // Zhang
echo $user-&gt;fullName;  // Zhang Wei

$user-&gt;age = 25;       // OK
$user-&gt;age = -1;       // throws ValueError
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;属性钩子也支持在接口中声明，实现类必须提供对应的钩子实现：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

interface HasFullName {
    public string $fullName { get; }
}

class Employee implements HasFullName {
    public function __construct(
        public string $firstName,
        public string $lastName,
    ) {}

    public string $fullName {
        get =&amp;gt; $this-&amp;gt;firstName . ' ' . $this-&amp;gt;lastName;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;相比传统方式，属性钩子减少了大量样板代码，且与 IDE 的自动补全、静态分析工具完美兼容。&lt;/p&gt;

&lt;h2&gt;三、非对称可见性（Asymmetric Visibility）：读写权限分离&lt;/h2&gt;
&lt;p&gt;PHP 8.4 引入了非对称可见性语法，允许属性的读取和写入使用不同的访问级别。这一特性在构建领域对象（Domain Object）和值对象（Value Object）时极为实用。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

class Order {
    // public 读取，private 写入
    public private(set) string $status = 'pending';

    // public 读取，protected 写入
    public protected(set) float $totalAmount = 0.0;

    public function confirm(): void {
        $this-&gt;status = 'confirmed'; // 内部可以修改
        $this-&gt;totalAmount = $this-&gt;calculateTotal();
    }

    private function calculateTotal(): float {
        // ... 计算逻辑
        return 299.99;
    }
}

$order = new Order();
echo $order-&gt;status;       // OK: &quot;pending&quot;
$order-&gt;status = 'paid';   // Error! 外部无法直接修改
$order-&gt;confirm();
echo $order-&gt;status;       // OK: &quot;confirmed&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;非对称可见性与只读属性（&lt;code&gt;readonly&lt;/code&gt;）的区别在于：&lt;code&gt;readonly&lt;/code&gt; 只能初始化一次，而非对称可见性允许类内部多次修改，外部只读。这在构建状态机、聚合根等场景下非常有用。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

// 结合构造器提升（Constructor Promotion）使用
class Product {
    public function __construct(
        public readonly int $id,
        public private(set) string $name,
        public private(set) float $price,
        public private(set) int $stock = 0,
    ) {}

    public function restock(int $quantity): void {
        $this-&gt;stock += $quantity;
    }

    public function rename(string $name): void {
        $this-&gt;name = $name;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;四、全新数组函数：array_find、array_find_key、array_any、array_all&lt;/h2&gt;
&lt;p&gt;PHP 8.4 新增了 4 个实用的数组函数，填补了长期以来需要手写循环或使用 &lt;code&gt;array_filter&lt;/code&gt; 变通方案的空缺：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

$users = [
    ['id' =&gt; 1, 'name' =&gt; 'Alice', 'age' =&gt; 28, 'active' =&gt; true],
    ['id' =&gt; 2, 'name' =&gt; 'Bob',   'age' =&gt; 17, 'active' =&gt; false],
    ['id' =&gt; 3, 'name' =&gt; 'Carol', 'age' =&gt; 32, 'active' =&gt; true],
];

// array_find：返回第一个匹配的元素
$firstActive = array_find($users, fn($u) =&amp;gt; $u['active']);
// ['id' =&gt; 1, 'name' =&gt; 'Alice', ...]

// array_find_key：返回第一个匹配元素的键
$minorKey = array_find_key($users, fn($u) =&amp;gt; $u['age'] &amp;lt; 18);
// 1 (Bob 的索引)

// array_any：至少有一个元素满足条件
$hasMinor = array_any($users, fn($u) =&amp;gt; $u['age'] &amp;lt; 18);
// true

// array_all：所有元素都满足条件
$allActive = array_all($users, fn($u) =&amp;gt; $u['active']);
// false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这些函数在处理集合数据时非常高效，且比 &lt;code&gt;array_filter + reset&lt;/code&gt; 的组合更语义化、可读性更强。在 Laravel、Symfony 等框架的 Service 层中，这些新函数将大幅简化代码。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

// 实战：在商品列表中查找第一个有库存且价格在预算内的商品
$products = getProductList();
$budget = 500.0;

$suitable = array_find(
    $products,
    fn($p) =&amp;gt; $p-&gt;stock &amp;gt; 0 &amp;amp;&amp;amp; $p-&gt;price &amp;lt;= $budget
);

if ($suitable) {
    echo &quot;推荐商品：{$suitable-&gt;name}，售价：{$suitable-&gt;price}&quot;;
} else {
    echo &quot;暂无符合条件的商品&quot;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;五、懒对象（Lazy Objects）：按需实例化，提升性能&lt;/h2&gt;
&lt;p&gt;PHP 8.4 在 &lt;code&gt;ReflectionClass&lt;/code&gt; 中内置了懒对象支持，无需第三方库即可实现延迟实例化。这一特性对 DI 容器、ORM 延迟加载、代理对象场景极为重要。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

class DatabaseConnection {
    public function __construct(
        private string $dsn,
        private string $username,
        private string $password,
    ) {
        echo &quot;Connecting to database...\n&quot;; // 真正连接时才执行
        // new PDO($this-&gt;dsn, $this-&gt;username, $this-&gt;password);
    }

    public function query(string $sql): array {
        // ...
        return [];
    }
}

// 创建懒对象——此时不会调用构造器
$reflector = new ReflectionClass(DatabaseConnection::class);
$db = $reflector-&gt;newLazyGhost(function (DatabaseConnection $instance) {
    // 初始化回调：第一次访问属性时触发
    $instance-&gt;__construct(
        dsn: 'mysql:host=localhost;dbname=myapp',
        username: 'root',
        password: 'secret'
    );
});

echo &quot;Lazy object created.\n&quot;; // 不会打印 &quot;Connecting...&quot;

// 直到第一次真正使用时，才会初始化
$result = $db-&gt;query('SELECT * FROM users'); // 现在才连接数据库
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;懒对象分为两种类型：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Lazy Ghost&lt;/strong&gt;：对同一个对象实例进行延迟初始化，初始化后对象身份不变&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Lazy Proxy&lt;/strong&gt;：使用代理包装真实对象，适合不能直接控制构造器的场景&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

// Lazy Proxy 示例
$reflector = new ReflectionClass(DatabaseConnection::class);
$proxy = $reflector-&gt;newLazyProxy(function (DatabaseConnection $proxy) {
    return new DatabaseConnection('mysql:host=prod-server', 'app', 'prod_secret');
});

// 代理对象与真实对象是不同实例
// 适用于需要替换底层实例的场景（如切换数据库连接）
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;六、HTML5 解析器：全新的 DOM 扩展&lt;/h2&gt;
&lt;p&gt;PHP 长期依赖基于 libxml 的 HTML 解析器，对 HTML5 的支持存在诸多缺陷。PHP 8.4 引入了基于 Lexbor 引擎的全新 HTML5 解析器，通过新的 &lt;code&gt;Dom\HTMLDocument&lt;/code&gt; 和 &lt;code&gt;Dom\XMLDocument&lt;/code&gt; 类提供支持。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

// 旧方式（libxml，对 HTML5 支持不完整）
$oldDoc = new DOMDocument();
@$oldDoc-&gt;loadHTML($html); // 需要 @ 抑制错误

// 新方式（PHP 8.4，基于 Lexbor，完整支持 HTML5）
$doc = Dom\HTMLDocument::createFromString($html, LIBXML_NOERROR);

// 支持现代 CSS 选择器（querySelector）
$title = $doc-&gt;querySelector('h1.title');
$items = $doc-&gt;querySelectorAll('.nav-item');

foreach ($items as $item) {
    echo $item-&gt;textContent . &quot;\n&quot;;
}

// 从 URL 加载（内部使用 file_get_contents）
// $doc = Dom\HTMLDocument::createFromFile('https://example.com');

// 序列化输出
echo $doc-&gt;saveHTML();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;新解析器的优势：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;完整支持 HTML5 标准，不再需要 &lt;code&gt;@&lt;/code&gt; 压制错误&lt;/li&gt;
  &lt;li&gt;支持 &lt;code&gt;querySelector&lt;/code&gt; / &lt;code&gt;querySelectorAll&lt;/code&gt; CSS 选择器&lt;/li&gt;
  &lt;li&gt;支持命名空间感知的节点操作&lt;/li&gt;
  &lt;li&gt;与浏览器行为一致，爬虫和内容处理场景更可靠&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;七、其他重要改进与升级建议&lt;/h2&gt;
&lt;p&gt;除了上述主要特性，PHP 8.4 还包含以下值得关注的改进：&lt;/p&gt;

&lt;h3&gt;PDO 驱动子类&lt;/h3&gt;
&lt;p&gt;PHP 8.4 引入了 &lt;code&gt;Pdo\Mysql&lt;/code&gt;、&lt;code&gt;Pdo\Sqlite&lt;/code&gt;、&lt;code&gt;Pdo\Pgsql&lt;/code&gt; 等 PDO 驱动子类，每个子类包含特定数据库的专有方法，类型系统更完善：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

// 现在可以使用类型声明指定具体的 PDO 子类
function mysqlQuery(Pdo\Mysql $pdo, string $sql): array {
    return $pdo-&gt;query($sql)-&gt;fetchAll();
}

$pdo = new Pdo\Mysql('mysql:host=localhost;dbname=test', 'root', '');
$rows = mysqlQuery($pdo, 'SELECT * FROM users');
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;BCMath 对象 API&lt;/h3&gt;
&lt;p&gt;BCMath 扩展新增了 &lt;code&gt;BcMath\Number&lt;/code&gt; 类，支持运算符重载，告别繁琐的函数调用：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

use BcMath\Number;

$price = new Number('19.99');
$qty   = new Number('3');
$tax   = new Number('0.08');

// 直接用运算符，无需 bcmul/bcadd
$subtotal = $price * $qty;          // 59.97
$taxAmount = $subtotal * $tax;      // 4.7976
$total = $subtotal + $taxAmount;    // 64.7676

echo $total-&gt;value;                 // &quot;64.7676&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;升级建议&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;使用 &lt;code&gt;php-codesniffer&lt;/code&gt; 或 &lt;code&gt;rector&lt;/code&gt; 工具自动检测和迁移废弃特性&lt;/li&gt;
  &lt;li&gt;PHP 8.4 废弃了隐式可空类型（&lt;code&gt;function foo(string $x = null)&lt;/code&gt;），需改为 &lt;code&gt;?string&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;建议先在测试环境升级，运行完整测试套件后再上生产&lt;/li&gt;
  &lt;li&gt;Composer 依赖检查：&lt;code&gt;composer why-not php 8.4&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;推荐配合 PHPStan level 8 + Rector PHP 8.4 规则集做静态分析&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PHP 8.4 代表了 PHP 语言现代化进程中的重要里程碑。属性钩子和非对称可见性让面向对象编程更加优雅，新数组函数和懒对象提升了开发效率，HTML5 解析器解决了多年痛点。现在就开始升级，享受这些特性带来的生产力提升吧！&lt;/p&gt;
</description><pubDate>Sat, 09 May 2026 08:06:22 +0800</pubDate></item><item><title>PHP 8.1 Fibers 实战：用协程重塑高并发异步编程</title><link>https://blog.resmic.cn/post/257.html</link><description>&lt;p&gt;&lt;img src=&quot;https://blog.resmic.cn/zb_users/upload/2026/05/20260508080612177819877256867.jpg&quot; alt=&quot;封面&quot; style=&quot;width:100%;&quot;/&gt;&lt;/p&gt;&lt;h2&gt;什么是 PHP Fibers？&lt;/h2&gt;&lt;p&gt;PHP 8.1 引入了 Fibers（纤程），这是 PHP 并发编程领域的重大革新。Fibers 提供了一种轻量级的协作式多任务机制，让开发者可以在单线程中实现类似协程的效果，无需依赖多进程或多线程。&lt;/p&gt;&lt;p&gt;与传统的同步代码不同，Fibers 允许代码在执行过程中主动&amp;quot;暂停&amp;quot;自身，将控制权交还给调用方，之后再从暂停点继续执行。这种机制特别适合处理 I/O 密集型任务，如数据库查询、HTTP 请求等。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;轻量级&lt;/strong&gt;：每个 Fiber 只占用极少内存，可以创建大量并发 Fiber&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;可控性强&lt;/strong&gt;：完全由开发者控制暂停和恢复的时机&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;无需扩展&lt;/strong&gt;：PHP 8.1+ 内置支持，无需安装额外扩展&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;异常安全&lt;/strong&gt;：支持在 Fiber 内部抛出和捕获异常&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Fibers 核心 API 详解&lt;/h2&gt;&lt;p&gt;PHP Fibers 的核心 API 非常简洁，主要围绕 &lt;code&gt;Fiber&lt;/code&gt; 类展开：&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

//&amp;nbsp;创建一个&amp;nbsp;Fiber
$fiber&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Fiber(function():&amp;nbsp;string&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$value&amp;nbsp;=&amp;nbsp;Fiber::suspend(&amp;#39;第一次暂停&amp;#39;);&amp;nbsp;&amp;nbsp;//&amp;nbsp;暂停并传递值给外部
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;从外部收到:&amp;nbsp;{$value}\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$value2&amp;nbsp;=&amp;nbsp;Fiber::suspend(&amp;#39;第二次暂停&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;再次从外部收到:&amp;nbsp;{$value2}\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;&amp;#39;最终返回值&amp;#39;;
});

//&amp;nbsp;启动&amp;nbsp;Fiber，获取第一次&amp;nbsp;suspend&amp;nbsp;的值
$firstSuspendedValue&amp;nbsp;=&amp;nbsp;$fiber-&amp;gt;start();
echo&amp;nbsp;&amp;quot;Fiber&amp;nbsp;第一次暂停，传来:&amp;nbsp;{$firstSuspendedValue}\n&amp;quot;;

//&amp;nbsp;恢复&amp;nbsp;Fiber，向它传值，并获取第二次&amp;nbsp;suspend&amp;nbsp;的值
$secondSuspendedValue&amp;nbsp;=&amp;nbsp;$fiber-&amp;gt;resume(&amp;#39;hello&amp;#39;);
echo&amp;nbsp;&amp;quot;Fiber&amp;nbsp;第二次暂停，传来:&amp;nbsp;{$secondSuspendedValue}\n&amp;quot;;

//&amp;nbsp;再次恢复，Fiber&amp;nbsp;结束
$fiber-&amp;gt;resume(&amp;#39;world&amp;#39;);

//&amp;nbsp;获取返回值
echo&amp;nbsp;&amp;quot;Fiber&amp;nbsp;返回:&amp;nbsp;&amp;quot;&amp;nbsp;.&amp;nbsp;$fiber-&amp;gt;getReturn()&amp;nbsp;.&amp;nbsp;&amp;quot;\n&amp;quot;;&lt;/pre&gt;&lt;p&gt;输出结果为：&lt;/p&gt;&lt;pre&gt;Fiber&amp;nbsp;第一次暂停，传来:&amp;nbsp;第一次暂停
从外部收到:&amp;nbsp;hello
Fiber&amp;nbsp;第二次暂停，传来:&amp;nbsp;第二次暂停
再次从外部收到:&amp;nbsp;world
Fiber&amp;nbsp;返回:&amp;nbsp;最终返回值&lt;/pre&gt;&lt;h2&gt;实战：构建简单的异步任务调度器&lt;/h2&gt;&lt;p&gt;Fibers 最典型的应用场景是构建异步任务调度器。下面是一个简单但完整的示例，展示如何用 Fibers 模拟并发执行多个任务：&lt;/p&gt;&lt;pre&gt;&amp;lt;?php

class&amp;nbsp;SimpleScheduler
{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;array&amp;nbsp;$fibers&amp;nbsp;=&amp;nbsp;[];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private&amp;nbsp;array&amp;nbsp;$queue&amp;nbsp;=&amp;nbsp;[];

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;addTask(callable&amp;nbsp;$callback):&amp;nbsp;void
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;fibers[]&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Fiber($callback);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;function&amp;nbsp;run():&amp;nbsp;void
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;启动所有&amp;nbsp;Fiber
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;foreach&amp;nbsp;($this-&amp;gt;fibers&amp;nbsp;as&amp;nbsp;$fiber)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;queue[]&amp;nbsp;=&amp;nbsp;fn()&amp;nbsp;=&amp;gt;&amp;nbsp;$fiber-&amp;gt;start();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;事件循环
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;(!empty($this-&amp;gt;queue))&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$task&amp;nbsp;=&amp;nbsp;array_shift($this-&amp;gt;queue);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$fiber&amp;nbsp;=&amp;nbsp;$task();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;($fiber&amp;nbsp;instanceof&amp;nbsp;Fiber&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;!$fiber-&amp;gt;isTerminated())&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;Fiber&amp;nbsp;尚未结束，重新加入队列
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this-&amp;gt;queue[]&amp;nbsp;=&amp;nbsp;fn()&amp;nbsp;=&amp;gt;&amp;nbsp;$fiber-&amp;gt;resume();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}

$scheduler&amp;nbsp;=&amp;nbsp;new&amp;nbsp;SimpleScheduler();

$scheduler-&amp;gt;addTask(function()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;[任务A]&amp;nbsp;开始执行\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Fiber::suspend();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;[任务A]&amp;nbsp;第二阶段\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Fiber::suspend();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;[任务A]&amp;nbsp;完成\n&amp;quot;;
});

$scheduler-&amp;gt;addTask(function()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;[任务B]&amp;nbsp;开始执行\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Fiber::suspend();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;[任务B]&amp;nbsp;第二阶段\n&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Fiber::suspend();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo&amp;nbsp;&amp;quot;[任务B]&amp;nbsp;完成\n&amp;quot;;
});

$scheduler-&amp;gt;run();&lt;/pre&gt;&lt;p&gt;这个示例展示了任务交替执行的核心思想——这也是 ReactPHP、Amp 等异步框架的底层实现原理。&lt;/p&gt;&lt;h2&gt;Fibers 与 Promise/异步框架集成&lt;/h2&gt;&lt;p&gt;单独使用 Fibers 的场景相对有限，它真正的威力在于与异步框架结合。以 Amp v3 为例，Fibers 是其核心基础：&lt;/p&gt;&lt;pre&gt;&amp;lt;?php
//&amp;nbsp;使用&amp;nbsp;Amp&amp;nbsp;v3（基于&amp;nbsp;Fibers）
use&amp;nbsp;Amp\Http\Client\HttpClientBuilder;
use&amp;nbsp;function&amp;nbsp;Amp\async;
use&amp;nbsp;function&amp;nbsp;Amp\await;

$client&amp;nbsp;=&amp;nbsp;HttpClientBuilder::buildDefault();

//&amp;nbsp;并发发起多个&amp;nbsp;HTTP&amp;nbsp;请求
$futures&amp;nbsp;=&amp;nbsp;[
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;async(fn()&amp;nbsp;=&amp;gt;&amp;nbsp;$client-&amp;gt;request(new&amp;nbsp;Request(&amp;#39;https://api.example.com/users&amp;#39;))),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;async(fn()&amp;nbsp;=&amp;gt;&amp;nbsp;$client-&amp;gt;request(new&amp;nbsp;Request(&amp;#39;https://api.example.com/posts&amp;#39;))),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;async(fn()&amp;nbsp;=&amp;gt;&amp;nbsp;$client-&amp;gt;request(new&amp;nbsp;Request(&amp;#39;https://api.example.com/comments&amp;#39;))),
];

//&amp;nbsp;等待所有请求完成
[$usersResp,&amp;nbsp;$postsResp,&amp;nbsp;$commentsResp]&amp;nbsp;=&amp;nbsp;await($futures);

echo&amp;nbsp;&amp;quot;用户数据:&amp;nbsp;&amp;quot;&amp;nbsp;.&amp;nbsp;$usersResp-&amp;gt;getBody()-&amp;gt;buffer()&amp;nbsp;.&amp;nbsp;&amp;quot;\n&amp;quot;;
echo&amp;nbsp;&amp;quot;文章数据:&amp;nbsp;&amp;quot;&amp;nbsp;.&amp;nbsp;$postsResp-&amp;gt;getBody()-&amp;gt;buffer()&amp;nbsp;.&amp;nbsp;&amp;quot;\n&amp;quot;;&lt;/pre&gt;&lt;p&gt;相比传统的回调地狱或 Promise 链式调用，基于 Fibers 的代码看起来就像同步代码，但实际是并发执行的。这大幅降低了异步编程的心智负担。&lt;/p&gt;&lt;h2&gt;性能对比与最佳实践&lt;/h2&gt;&lt;p&gt;在实际项目中使用 Fibers 时，需要注意以下几点：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;适合 I/O 密集型场景&lt;/strong&gt;：数据库查询、Redis 操作、HTTP 请求等，并发效果显著&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;不适合 CPU 密集型场景&lt;/strong&gt;：Fibers 是协作式的，CPU 计算不会主动让出控制权&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;避免在 Fiber 中使用阻塞函数&lt;/strong&gt;：如 &lt;code&gt;sleep()&lt;/code&gt;、&lt;code&gt;file_get_contents()&lt;/code&gt; 等会阻塞整个进程&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;错误处理要完善&lt;/strong&gt;：未捕获的异常会终止整个 Fiber，需要做好异常边界&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;配合 Swoole 或 OpenSwoole&lt;/strong&gt;：在常驻内存的服务中，Fibers 的优势更加突出&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;简单性能测试数据显示，在处理 100 个并发 HTTP 请求时，使用 Fibers 的异步方案比传统同步方案快 8-15 倍，内存占用降低约 40%。&lt;/p&gt;&lt;p&gt;PHP Fibers 为 PHP 带来了现代化的并发编程能力。随着 Amp、ReactPHP 等框架对 Fibers 的全面支持，PHP 在高并发场景下的表现已经不逊色于 Node.js 和 Go。对于后端开发者来说，现在正是学习和实践 PHP 异步编程的最佳时机。&lt;/p&gt;</description><pubDate>Fri, 08 May 2026 08:09:41 +0800</pubDate></item></channel></rss>