PHP Migrating 8.3 to 8.4
简介 PHP 8.4 引入了许多新特性,如属性钩子(Property Hooks)、非对称可见性(Asymmetric Visibility)以及更新的 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 属性可以公开读取但只能私有写入。 可空类型解包 PHP 8.4 引入了可空类型解包操作符 ??=,可以在一行代码中解包可空值: ...
PHP Migrating 8.2 to 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 contains many new features, such as explicit typing of class constants, deep-cloning of readonly properties and additions to the randomness functionality. New Features 8.3 // Typed class constants // Include class, trait, interface, enum trait TestTrait { final protected const string TEST = 'test'; } interface TestInterface { public const string TEST = 'test'; } enum TestEnum: string { public const string TEST = 'test'; } // Similar to return types, class constant types can also be "narrowed", or kept the same in a sub-class or an implementation. This follows LSP. class ParentClass { public const string|int VALUE = 'MyValue'; } class ChildClass extends ParentClass { public const string VALUE = 'MyValue'; } json_validate('[1, 2, 3]'); // true json_validate('{1, 2, 3]'); // false // Dynamic class constant and Enum member fetch support class Foo { const PHP = 'PHP 8.3'; } $searchableConstant = 'PHP'; echo constant(Foo::class . "::{$searchableConstant}"); echo Foo::{$searchableConstant}; // instead of `constant()` // Random extension // public function getFloat( // float $min, float $max, // \Random\IntervalBoundary $boundary = \Random\IntervalBoundary::ClosedOpen // ): float // // enum IntervalBoundary { // case ClosedOpen; // case ClosedClosed; // case OpenClosed; // case OpenOpen; // } $rng = new Random\Randomizer(); echo $rng->getFloat(0, 10, \Random\IntervalBoundary::OpenOpen); // 6.7810757668383 // Generate a random number in the range 0 <= and < 1: $rng = new Random\Randomizer(); echo $rng->nextFloat(); // 0.21185336351144 // Returns a random number sequence of a requested length ($length parameter), only containing a bytes from the requested series of bytes ($string parameter). $rng = new Random\Randomizer(); $chars = 'AEIOU'; echo $rng->getBytesFromString($chars, 1); // "E" echo $rng->getBytesFromString($chars, 5); // "AIIEO" // #[\Override] attribute // PHP enforces that the targeted class method must be overriding or implementing a parent/interface method. class ParentClass { protected function demo() {} } class ChildClass extends ParentClass { #[\Override] protected function demo() {} // ✅ 明确覆盖 #[\Override] protected function demmo() {} // ❌ Fatal error (拼写错误) } New Functions 8.3 // Pad a multibyte string to a certain length with another multibyte string echo mb_str_pad('中国', 6, '爱', STR_PAD_RIGHT) . "\n"; echo mb_str_pad('中国', 6, '爱', STR_PAD_LEFT) . "\n"; echo mb_str_pad('中国人', 6, '爱', STR_PAD_BOTH) . "\n"; // 中国爱爱爱爱 // 爱爱爱爱中国 // 爱中国人爱爱 Backward Incompatible Changes 8.3 // Assigning a negative index n to an empty array will now make sure that the next index is n + 1 instead of 0. $arr = []; $arr[-5] = 'a'; $arr[] = 'b'; var_dump($arr); // PHP8.3 → [-5 => 'a', -4 => 'b'] // PHP <8.3 → [-5 => 'a', 0 => 'b'] – EOF – ...
PHP Migrating 8.1 to 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 https://github.com/symfony/polyfill/tree/1.x/src/Php82 PHP 8.2 brings type-system improvements for expressive and fine-grained type-safety, readonly classes, sensitive parameter redaction support, new random extension, and many new features along with several changes to streamline and modernize PHP language. New Features 8.2 // Readonly Classes // Complete class properties become immutable when declared readonly readonly class User { public function __construct(public string $username, public string $email) { } } // All properties automatically become readonly $user = new User('john_doe', 'john@example.com'); $user->email = 'new@example.com'; // Fatal error: Uncaught Error: Cannot modify readonly property User::$email // Combine union and intersection types using Disjunctive Normal Form // 析取范式,允许通过 |(联合)和 &(交叉)运算符组合类型 function process((Countable&Iterator)|null $item) { return $item; } // Use null, true, false as independent types function alwaysFalse(): false {} function alwaysNull(): null {} function alwaysTrue(): true {} // Define constants directly in traits trait NetworkTrait { public const TIMEOUT = 60; } // Hide sensitive data in stack traces function hashPassword(#[\SensitiveParameter] string $password) { debug_print_backtrace(); } hashPassword('secret123'); // Before #0 /home/user/scripts/code.php(7): hashPassword('secret123') // PHP8.2 #0 /home/user/scripts/code.php(7): hashPassword(Object(SensitiveParameterValue)) // Consolidated RNG functions with OOP interface $randomizer = new \Random\Randomizer(); echo $randomizer->getInt(1, 100); // Random integer New Functions 8.2 // Parses any data size recognized by PHP INI values ini_parse_quantity('256M'); // 268435456 Deprecated Features 8.2 // ${var} String Interpolation Deprecated $name = 'Li'; echo "Hello ${name}"; // should be `{$name}` // Deprecated: Using ${var} in strings is deprecated, use {$var} instead $var = 'name'; echo "Hello ${$var}"; // should be `{$$var}` // Deprecated: Using ${expr} (variable variables) in strings is deprecated, use {${expr}} – EOF – ...
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 ...
手把手教你落地 DDD Part1
01 小传 Domain-Driven Design 是一种开发复杂软件的系统化的 方法学和思想。 面向对象方法学还不能很好地应用于企业应用原因: 很多开发人员走了一条只重技术不重业务的弯路。 围绕业务进行开发的方法本身就不好学。 早期面向对象方法学主要考虑的是建模技术,很少考虑协作问题。 难以适应变化。 从业务出发进行系统的设计。 DDD 从面向对象和敏捷中提炼出了一套原则、模式和实践,使面向对象方法学在企业应用中更加容易学习和掌握。 如果没有迭代开发、持续重构、测试驱动、持续集成等敏捷实践的支持,构建良好的领域模型并在代码上落地是很困难的。 微服务是一种架构风格(或者说架构模式)。 02 迭代一 领域专家需要对业务有总体性和本质性的把握,同时对业务发展也要有一定前瞻性,心里要有一盘棋。 捕获行为需求(事件风暴)-> 领域建模 -> 结构设计 -> 数据库设计 -> 代码实现 |------- 模型的建立 --------| |--------- 模型的实现 ------| 03 事件风暴 上 识别领域事件;在业务流程中发生了什么? 识别命令;谁,做了什么事,导致领域事件的发生? 识别领域名词;命令、事件和那些名词性概念有关? 领域事件表示的是,业务流程中每个步骤引发的结果。一般是完成时 + 被动语态。例:订单已被提交。 在 DDD 中的各种命名,一般都优先使用约定俗成的 业务术语。 不要把技术事件当成领域事件。 查询功能不算领域事件。领域事件应该是对某样事物产生了影响,并被记录的事情。 参加的人,各自写出领域事件 -> 一起讨论,统一理解。这种先发散,后收敛,反复迭代的过程实际上就是一种头脑风暴。“协作”才是事件风暴的精髓。 04 事件风暴 下 首先我们看看领域事件的作用。从代码实现的角度来看,领域事件一般会对应一段代码逻辑,这段逻辑可能会最终改变数据库中的数据。另外,在事件驱动的架构中,一个领域事件可能会表现为一个向外部发送的异步消息。 那命令的作用体现在哪儿呢?领域建模时,我们可以通过对命令的走查(walkthrough),细化和验证领域模型。在实现层面,一个命令可能对应前端的一个操作,例如按下按钮;对于后端而言,一个命令可能对应一个 API。 再来说命令的执行者。在领域建模时,执行者可能本身就是一个领域对象,也可能是领域对象充当的角色,或者是权限管理中的一个角色。 如果要体现严格的时间顺序,我们可以用流程图、用顺序图等方法,但事件风暴不必关注这一点。 我们是把每个小步骤都当作独立的一个事务来看待,还是把它们合起来作为同一个事务。另外,可以设想,如果每个小步骤都向外界发出一个领域事件,对系统后续的功能是不是有意义。原则上宜粗不宜细。 抓住协作、统一语言、识别领域名词等要点。 事件风暴是一种通过协作的方式捕获行为需求的方法,在这个过程里,业务人员和技术人员一起消化领域知识、形成统一语言、并为领域建模奠定基础。 References –
正则表达式
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) ++:同贪婪一样匹配最长。不过在独占量词模式下,正则表达式尽可能长地去匹配字符串,一旦匹配不成功就会结束匹配而 不会回溯。 ...
Vim 实用技巧必知必会
安装 yum list installed | grep vim # vim-X11.x86_64 2:7.4.629-8.el7_9 @updates # vim-common.x86_64 2:7.4.629-8.el7_9 @updates # vim-enhanced.x86_64 2:7.4.629-8.el7_9 @updates # vim-filesystem.x86_64 2:7.4.629-8.el7_9 @updates # vim-minimal.x86_64 2:7.4.629-8.el7_9 @updates # https://gist.github.com/yevrah/21cdccc1dc65efd2a4712781815159fb # Update to Vim8 on CentOS 7 rpm -Uvh http://mirror.ghettoforge.org/distributions/gf/gf-release-latest.gf.el7.noarch.rpm rpm --import http://mirror.ghettoforge.org/distributions/gf/RPM-GPG-KEY-gf.el7 yum -y remove vim-minimal vim-common vim-enhanced yum -y --enablerepo=gf-plus install vim-enhanced vim-filesystem sudo vim --version # VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Sep 18 2016 14:42:40) yum list installed | grep vim # vim-common.x86_64 2:8.0.003-1.gf.el7 @gf-plus # vim-enhanced.x86_64 2:8.0.003-1.gf.el7 @gf-plus # vim-filesystem.x86_64 2:8.0.003-1.gf.el7 @gf-plus # vim-minimal.x86_64 2:8.0.003-1.gf.el7 @gf-plus # 中文帮助 mkdir -p ~/.vim/pack/my/start cd ~/.vim/pack/my/start git clone git://github.com/yianwillis/vimcdoc.git # 自带教程 LANG=zh_CN.UTF-8 vimtutor
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 网络共享存储 … ...
Kubernetes 入门实战 Part2
17 多节点的 Kubernetes 集群 在腾讯云 TencentOS Server 3.1 (TK4) 下测试: master SA3.MEDIUM4 2 核 4GB 5Mbps worker S5.SMALL2 1 核 2GB 1Mbps worker S5.SMALL2 1 核 2GB 1Mbps # 修改源 https://mirrors.cloud.tencent.com/ mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.cloud.tencent.com/repo/centos7_base.repo yum clean all yum makecache # install docker yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine yum install -y yum-utils yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin systemctl start docker docker -v docker run hello-world 一些准备工作: ...
Kubernetes 入门实战 Part1
01 初识 Docker apt install -y docker.io service docker start usermod -aG docker ${USER} docker version docker info docker ps docker pull busybox # show all images docker images https://docs.docker.com/get-started/overview/ 02 被隔离的进程 docker pull alpine docker run -it alpine sh cat /etc/os-release 隔离资源,保证系统安全,提高资源的利用率。 资源隔离提供了三种技术:namespace、 cgroup、chroot(pivot_rott)。 03 容器化的应用 Build once, Run anywhere. 应用程序不再直接和操作系统打交道,而是封装成镜像,再交给容器环境去运行。 # remove image docker rmi busybox # 开启一个交互式操作的 Shell docker run -it busybox # 在后台运行 docker run -d busybox # 为容器起一个名字 docker run -d --name xxx busybox # 不保存容器,只要运行完毕就自动清除 docker run --rm busybox echo "hello docker" docker stop xxx # remove container docker rm xxx # show all container docker ps -a docker exec xxx echo "hello docker" 05 镜像仓库 https://github.com/docker-library/official-images https://hub.docker.com/u/library 用户名/应用名:标签 官方镜像用户名是 library。 ...