PHP Migrating 8.4 to 8.5

简介 PHP 8.5 引入了许多令人兴奋的新特性,包括管道运算符(Pipe Operator)、URI 扩展、Clone With 语法、#[\NoDiscard] 属性等。本文将介绍主要变化和如何从 PHP 8.4 迁移到 PHP 8.5。 参考资源 在线测试环境:https://3v4l.org/ 官方发布说明:https://www.php.net/releases/8.5/en.php 迁移指南:https://www.php.net/manual/en/migration85.php 更新详情:https://php.watch/versions/8.5 PHP 8.5 新特性 管道运算符(Pipe Operator) PHP 8.5 引入了管道运算符 |>,使函数链式调用更加清晰易读: // PHP 8.5 之前 - 嵌套函数调用,难以阅读 $slug = strtolower(str_replace('.', '', str_replace(' ', '-', trim($title)))); // PHP 8.5 - 使用管道运算符,从左到右清晰阅读 $slug = $title |> trim(...) |> (fn($str) => str_replace(' ', '-', $str)) |> (fn($str) => str_replace('.', '', $str)) |> strtolower(...); 管道运算符将左侧的值作为右侧函数的第一个参数传递,实现函数组合的链式调用。 URI 扩展 PHP 8.5 新增了内置的 URI 扩展,遵循 RFC 3986 和 WHATWG URL 标准来解析和处理 URL。 URI 与 URL 的关系:URI(统一资源标识符)用于标识资源,URL(统一资源定位符)用于定位资源。所有 URL 都是 URI,但不是所有 URI 都是 URL。该扩展命名为 URI 是因为它能处理更广泛的标识符格式。 ...

January 5, 2026 · 5 min · 952 words · Me, LLM

NGINX 启用 HTTP/3

简介 HTTP/2 解决了"多路复用、头部压缩、优先级"等 HTTP/1.x 的瓶颈,但仍受 TCP 先天限制。 HTTP/3 则把同样的语义搬到 QUIC。Quick UDP Internet Connections 是 Google 设计的一种基于 UDP 的多路复用安全传输层协议。标准化后,HTTP/3 = HTTP over QUIC。 层级 HTTP/2 HTTP/3 传输 TCP(必)+ TLS 1.2/1.3(多数场景) QUIC(UDP 之上)+ TLS 1.3(强制) 流(Stream) Mux 在 TCP 里的逻辑流 Mux 在 QUIC 原生流 头压缩 HPACK QPACK(避免队头阻塞) HTTP/2 浏览器要求必须跑在 TLS 之上(ALPN=“h2”)。栈变为 HTTP/2 → TLS → TCP → IP。 HTTP/3 使用 QUIC 替换 TCP,栈变为 HTTP/3 → QUIC(拥塞/重传)→ UDP → IP,加密集成在 QUIC(基于 TLS 1.3)。 Mux 即 multiplex,多路复用。 HTTP/2 必须顺序传输,而 HTTP/3 支持乱序。 如果沿用 HPACK,丢一个 UDP 包就会让所有流的头部解码卡住,因此 IETF 为 HTTP/3 设计了 QPACK 来"避开队头阻塞(Head-of-Line Blocking, HoL)"。 连接迁移:通过 Connection ID 识别会话,IP 或端口改变(如移动网络/Wi-Fi 切换)无需重新建立连接。 使用 HTTP/3 的网站: ...

June 27, 2025 · 2 min · 413 words · Me, LLM

在本地环境使用 HTTPS

公网环境使用 HTTPS 参考:使用 Certbot 获取 Let’s Encrypt 颁发的 TLS 证书 | ZYF.IM。 简介 HTTPS(HyperText Transfer Protocol Secure)是在 HTTP 之上通过 TLS/SSL 实现加密的安全通信协议,用来保护浏览器与服务器之间的数据机密性、完整性与身份可信性。 开始实验 mkcert 会在本地生成一套根 CA(包含根证书和私钥),并把根证书导入系统/浏览器的信任列表。随后,它用这套 CA 的私钥为 localhost 等域名签发服务器证书;因为根证书已被信任,浏览器访问时就会把服务器证书视为可信。 brew install mkcert mkcert -install mkcert localhost # The certificate is at "./localhost.pem" and the key at "./localhost-key.pem" ✅ # vi default.conf server { listen 443 ssl; server_name localhost; ssl_certificate /etc/ssl/certs/localhost.pem; ssl_certificate_key /etc/ssl/certs/localhost-key.pem; # 只允许 TLSv1.2 和 TLSv1.3 协议,显式禁止 TLSv1.0 和 TLSv1.1 协议 ssl_protocols TLSv1.2 TLSv1.3; # 只保留高强度、带身份验证、且不使用 MD5 的 TLS 1.2(及以下)套件 ssl_ciphers HIGH:!aNULL:!MD5; # 优先使用服务器端加密套件 ssl_prefer_server_ciphers on; location / { root /usr/share/nginx/html; index index.html index.htm; } } docker run -d --name nginx-ssl \ -p 8443:443 \ -v ./default.conf:/etc/nginx/conf.d/default.conf:ro \ -v ./localhost.pem:/etc/ssl/certs/localhost.pem:ro \ -v ./localhost-key.pem:/etc/ssl/certs/localhost-key.pem:ro \ nginx:alpine # docker rm -f nginx-ssl # docker container restart nginx-ssl 测试 浏览器 浏览器访问 https://localhost:8443/,如果证书是绿色的,说明成功了。 ...

June 26, 2025 · 4 min · 669 words · Me, LLM

PHP Migrating 8.3 to 8.4

简介 PHP 8.4 引入了许多新特性,如属性钩子(Property Hooks)、非对称可见性(Asymmetric Visibility)、#[Deprecated] 属性以及更新的 DOM API 等。本文将介绍主要变化和如何进行迁移。 参考资源 在线测试环境:https://onlinephp.io/ 官方发布说明:https://www.php.net/releases/8.4/en.php 迁移指南:https://www.php.net/manual/en/migration84.php 更新详情:https://php.watch/versions/8.4 PHP 8.4 新特性 属性钩子与非对称可见性 // 属性钩子(Property Hooks)与非对称可见性(Asymmetric Visibility) class User { private bool $isModified = false; public function __construct(public private(set) string $first, private string $last) { } public string $fullName { get => $this->first . " " . $this->last; set { [$this->first, $this->last] = explode(' ', $value, 2); $this->isModified = true; } } } $user = new User("Ming", "Li"); echo $user->fullName; // 输出: Ming Li $user->fullName = "Hong Xiao"; echo $user->fullName; // 输出: Hong Xiao // 非对称可见性示例 echo $user->first; // 输出: Hong $user->first = "Hua"; // 错误: Fatal error: Uncaught Error: Cannot modify private(set) property User::$first 属性钩子允许我们定义属性的获取和设置行为,而非对称可见性允许我们为属性设置不同的读写权限。在上例中,$first 属性可以公开读取但只能私有写入。 #[Deprecated] 属性 PHP 8.4 引入了 #[Deprecated] 属性,可以用来标记已弃用的代码: ...

February 1, 2025 · 4 min · 741 words · Me, LLM

PHP Migrating 8.2 to 8.3

简介 PHP 8.3 引入了许多新特性,包括类型化类常量(Typed Class Constants)、#[\Override] 属性、json_validate() 函数、只读属性的深度克隆等。本文将介绍主要变化和如何从 PHP 8.2 迁移到 PHP 8.3。 参考资源 在线测试环境:https://onlinephp.io/ 官方发布说明:https://www.php.net/releases/8.3/en.php 迁移指南:https://www.php.net/manual/en/migration83.php 更新详情:https://php.watch/versions/8.3 PHP 8.3 新特性 类型化类常量(Typed Class Constants) PHP 8.3 允许为类常量声明类型,增强了类型安全性: interface DatabaseInterface { public const string ENGINE = 'mysql'; } trait ConfigTrait { final protected const int MAX_CONNECTIONS = 100; } enum Status: string { public const string DEFAULT = 'pending'; case Pending = 'pending'; case Active = 'active'; } class Database implements DatabaseInterface { use ConfigTrait; // 类型遵循 LSP(里氏替换原则),子类可以收窄类型 public const string ENGINE = 'postgresql'; } 类常量类型遵循里氏替换原则(LSP),子类可以收窄父类常量的类型: class ParentClass { public const string|int VALUE = 'MyValue'; } class ChildClass extends ParentClass { // ✅ 可以将 string|int 收窄为 string public const string VALUE = 'MyValue'; } #[\Override] 属性 新的 #[\Override] 属性确保方法确实覆盖了父类方法,有助于捕获拼写错误和简化重构: class ParentClass { protected function setUp(): void {} } class ChildClass extends ParentClass { #[\Override] protected function setUp(): void {} // ✅ 正确覆盖 #[\Override] protected function setUpP(): void {} // ❌ Fatal error: 父类没有该方法 } 这在重构时特别有用 - 如果父类方法被重命名或删除,PHP 会立即报错而不是静默失败。 ...

August 1, 2024 · 5 min · 912 words · Me, LLM

PHP Migrating 8.1 to 8.2

简介 PHP 8.2 引入了许多类型系统改进,包括只读类(Readonly Classes)、析取范式类型(DNF Types)、独立的 null、true、false 类型、敏感参数隐藏、新的 Random 扩展等。本文将介绍主要变化和如何从 PHP 8.1 迁移到 PHP 8.2。 参考资源 在线测试环境:https://onlinephp.io/ 官方发布说明:https://www.php.net/releases/8.2/en.php 迁移指南:https://www.php.net/manual/en/migration82.php 更新详情:https://php.watch/versions/8.2 PHP 8.2 新特性 只读类(Readonly Classes) PHP 8.2 允许将整个类声明为只读,类中的所有属性自动成为只读属性: readonly class User { public function __construct( public string $username, public string $email, ) {} } $user = new User('john_doe', 'john@example.com'); echo $user->username; // john_doe $user->email = 'new@example.com'; // Fatal error: Cannot modify readonly property User::$email 只读类的特性: 所有属性自动成为只读 不能有动态属性 所有属性必须有类型声明 子类也必须是只读的 析取范式类型(DNF Types) 析取范式(Disjunctive Normal Form)允许组合联合类型和交叉类型,交叉类型必须用括号分组: // 接受同时实现 Countable 和 Iterator 的对象,或者 null function process((Countable&Iterator)|null $item): int { return $item ? count($item) : 0; } // 更复杂的 DNF 类型示例 function handle( (HTMLRequest&RequestInterface)|APIRequest|null $request ): Response { // 处理请求 } DNF 类型必须遵循特定格式:交叉类型用括号包裹,再与其他类型用 | 连接。 ...

July 1, 2024 · 5 min · 1005 words · Me, LLM

MongoDB 高手课

04 特色及优势 对象模型,快速响应业务变化: 多形性:同一个集合中可以包含不同字段(类型)的文档对象。 动态性:线上修改数据模式,修改是应用与数据库均无须下线。 数据治理:支持使用JSONSchema 来规范数据模式。在保证模式灵活动态的前提下,提供数据治理能力。 快速的开发: 只存储在一个存储区读写。 反范式、无关联的组织极大优化查询速度。 程序 API 自然,开发速度快。 原生的高可用: Replica Set - 2 to 50 个成员,建议单数。 自恢复。 多中心容灾能力。 滚动服务,最小化服务终端。 横向扩展能力: 需要的时候无缝扩展。 应用全透明。 多种数据分布策略。 轻松支持 TB-PB 数量级。 06 基本操作 cloud.mongodb.com 云服务 样本数据 | geektime-mongodb-course tar -xvf dump.tar.gz mongorestore --uri="mongodb://root:root@10.130.0.12/?&authMechanism=SCRAM-SHA-1" // 插入 db.fruit.insertOne({name: "apple"}) db.fruit.insertMany([ {name: "apple"}, {name: "pear"}, {name: "orange"}, ]) // 查询 db.customers.find({username: "fmiller", name: "Elizabeth Ray"}) db.customers.find({username: /^f/}) db.customers.find({$or: [{username: /^f/}, {name: /^E/}]}) a <> 1 {a: {$ne: 1}} a > 1 {a: {$gt: 1}} a >= 1 {a: {$gte: 1}} a < 1 {a: {$lt: 1}} a <= 1 {a: {$lte: 1}} a=1 OR b=1 {$or: [{a: 1}, {b: 1}]} a IS NULL {a: {$exists: false}} a IS (1,2,3) {a: {$in: [1, 2, 3]}} // 同时满足 {$eleMatch: {"city": "Rome", "country": "USA"}} // 投影 projection // like select db.customers.find({username: /^f/}, {name: 0, email: 0}) db.customers.find({username: /^f/}, {_id: 1, name: 1}) // remove db.customers.remove({username: "abrown"}) // update db.customers.updateOne({username: "fmiller"}, {$set: {from: "China"}}) db.customers.updateMany({username: "fmiller"}, {$set: {from: "China"}}) // $set $unset // $push $pushAll $pop 数组操作 // $pull $pullAll 如果匹配,从数组中删除相应的对象 // $addToSet 如果不存在则增加一个值到数组 // drop db.fruit.drop() show collections db db.dropDatabase() show dbs 08 聚合查询 Aggregation Framework ...

April 19, 2023 · 7 min · 1333 words · Me

手把手教你落地 DDD

01 DDD 小传 DDD(Domain-Driven Design)由 Eric Evans 于 2003 年提出,本质是一套用于开发复杂软件的系统化方法学与思想,核心关注“领域建模”。它源于面向对象方法学与敏捷开发,可理解为“把面向对象做对”(OO Done right),并将建模、设计与落地实践更体系化。 传统面向对象在企业应用中常见问题是重技术轻业务、领域建模难以掌握、协作与沟通不足、难以适应频繁变化。DDD 通过模式、原则与实践(如通用语言、限界上下文、模型驱动设计等)促进业务与技术协作沉淀知识,并用“柔性设计/演进”避免过度设计、支持持续重构。 近年因数字化带来更高复杂度与变化,以及敏捷/DevOps 与 Spring Boot、微服务、整洁架构、事件驱动、CQRS 等生态成熟,DDD 才从“屠龙术”变成广泛可用的方法。 02 迭代一 企业管理系统 企业为了满足管理诉求,希望员工每周在系统中填报自己在哪些项目上花了多少时间,也就是所谓的报工时。 需求 核心对象/范围 主要功能(CRUD/流程) 关键规则/约束 关键字段/记录 多租户 租户(企业) 管理多个租户(企业) 每个租户代表一个使用 SaaS 的企业 — 人员与组织管理 部门、员工 部门:增删改查;员工:增删改查;员工分配部门 员工只能从属于一个部门 部门层级示例:开发中心 → 开发组;职能部门(人事/财务等) 项目管理 客户、合同、项目 客户:增删改查;合同:增删改查 + 开始/结束;项目:增删改查 + 开始/结束 客户对应客户经理;合同对应销售;项目对应项目经理;合同下可有多个项目 合同/项目开始时间、结束时间等 人员分配 项目成员关系 为项目分配人员;人员退出项目 项目可多人;员工可同时参与多个项目;需记录投入比例 投入百分比(人-项目) 工时登记 工时(周报/日记录) 员工每周填报工时;查询;修改;填写备注 仅当员工已分配到项目后,才可在该项目报工时 日期、项目、投入时长、备注 03 事件风暴 识别领域事件 领域事件是什么 **领域事件(Domain Event)**用来表达:在业务流程的某一步完成后,所引发并被业务关心的“结果”。 ...

March 1, 2023 · 2 min · 299 words · Me

正则表达式

00 regex101 regulex ihateregex 01 元字符 正则表达式 —— 字符串的规则。 元字符就是指那些在正则表达式中具有特殊意义的专用字符。 特殊单字符 . 任意字符(换行除外) \d 任意数字 \D 任意非数字 \w A-Za-z0-9_ \W \s 空白符 \S 空白符 \r 回车符 \n 换行符 \f 换页符 \t 制表符 \v 垂直制表符 范围 | 或 [abc] 多选一 [a-z] 之间 [^abc] 取反,不能是括号中的任意单个元素 量词 * 0<= + 1<= ? 0或1 {m} m {m,} m<= {m,n} m-n 02 量词与贪婪 贪婪(Greedy) *:匹配最长。在贪婪量词模式下,正则表达式会尽可能长地去匹配符合规则的字符串,且会回溯。 preg_match_all("/a*/i", "aaabb", $matches); var_dump($matches); 非贪婪(Reluctant) +?:匹配最短。在非贪婪量词模式下,正则表达式会匹配尽可能短的字符串。 ENV:Python3 import re re.findall(r'a*', 'aaabb') # 贪婪模式 # ['aaa', '', '', ''] re.findall(r'a*?', 'aaabb') # 非贪婪模式 # ['', 'a', '', 'a', '', 'a', '', '', ''] re.findall(r'".+"', '"the little cat" is a toy, it lokks "a little bad"') # 贪婪模式 # ['"the little cat" is a toy, it lokks "a little bad"'] re.findall(r'".+?"', '"the little cat" is a toy, it lokks "a little bad"') # 非贪婪模式 # ['"the little cat"', '"a little bad"'] 独占模式(Possessive) ++:同贪婪一样匹配最长。不过在独占量词模式下,正则表达式尽可能长地去匹配字符串,一旦匹配不成功就会结束匹配而 不会回溯。 ...

March 1, 2023 · 7 min · 1441 words · Me

Kubernetes 入门实战 Part3

24 PersistentVolume 数据持久化 PersistentVolume 属于集群的系统资源,是和 Node 平级的一种对象,Pod 对它没有管理权,只有使用权。 StorageClass 它抽象了特定类型的存储系统(比如 Ceph、NFS),在 PVC 和 PV 之间充当“协调人”的角色,帮助 PVC 找到合适的 PV。 # vim host-path-pv-pvc.yml apiVersion: v1 kind: PersistentVolume metadata: # 只有 10MB 容量的存储设备 name: host-10m-pv spec: # kubectl explain PersistentVolume.spec.storageClassName storageClassName: host-vol # kubectl explain PersistentVolume.spec.accessModes accessModes: # ReadWriteOnce:存储卷可读可写,但只能被一个节点上的 Pod 挂载。 # ReadOnlyMany:存储卷只读不可写,可以被任意节点上的 Pod 多次挂载。 # ReadWriteMany:存储卷可读可写,也可以被任意节点上的 Pod 多次挂载。 - ReadWriteOnce capacity: # Ki/Mi/Gi storage: 10Mi hostPath: path: /tmp/host-10m-pv/ --- # PVC 不表示实际的存储,而是一个“申请”或者“声明” apiVersion: v1 kind: PersistentVolumeClaim metadata: name: host-5m-pvc spec: storageClassName: host-vol accessModes: - ReadWriteOnce resources: requests: storage: 5Mi mkdir /tmp/host-10m-pv kubectl apply -f host-path-pv-pvc.yml kubectl get pv # NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE # host-10m-pv 10Mi RWO Retain Bound default/host-5m-pvc host-vol 4s kubectl get pvc # NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE # host-5m-pvc Bound host-10m-pv 10Mi RWO host-vol 6s # vim host-pvc-pod.yml apiVersion: v1 kind: Pod metadata: name: host-pvc-pod spec: volumes: - name: host-pvc-vol persistentVolumeClaim: claimName: host-5m-pvc containers: - name: ngx-pvc-pod image: nginx:alpine ports: - containerPort: 80 volumeMounts: - name: host-pvc-vol mountPath: /tmp kubectl apply -f host-pvc-pod.yml kubectl get pod -o wide kubectl exec -it host-pvc-pod -- sh cd /tmp && touch a.md # check in worker node /tmp/host-10m-pv/ 25 NFS 网络共享存储 … ...

February 24, 2023 · 1 min · 205 words · Me