php7的一些特性

性能提升:PHP7比PHP5.6性能提升了两倍。 Improved performance: PHP 7 is up to twice as fast as PHP 5.6
全面一致的64位支持。 Consistent 64-bit support
以前的许多致命错误,现在改成抛出异常。Many fatal errors are now Exceptions
移除了一些老的不在支持的SAPI(服务器端应用编程端口)和扩展。Removal of old and unsupported SAPIs and extensions
新增了空接合操作符。The null coalescing operator (??)
新增加了结合比较运算符。Combined comparison Operator (<=>)
新增加了函数的返回类型声明。Return Type Declarations
新增加了标量类型声明。Scalar Type Declarations
新增加匿名类。Anonymous Classes
打破一切


 

PHP7.2的变更:

核心语言变更:

l gettype()对已关闭资源的返回值,从”unkonw type”变为了”resource(closed)”

l 数组对象互转:数组强转为对象时整数键会转换为字符串属性名;对象转数组时,数字字符串属性名会转为整数键。

l 未加引号的字符串常量:对未定义常量的裸字符串引用,现在产生告警,后续会升级成error;

l object不能用作类名;

函数变更:

l 移除了register_globals相关代码;

l Session状态管理更加严格,session_start()、session_regenerate_id()等函数对无效操作会返回正确的布尔值。

废弃功能(7.2已废弃,8.0移除):

l create_function():应改用匿名函数:(function() use(){})

l __autoload():应改用spl_autoload_register()函数。

l assert()已废弃。

移除的扩展:

l Mysql改用PDO或mysqli

l mcrypt改用OpenSSL或Sodium();

l mssql改用PDO_SQLSRV或sqlsrv;

PHP7核心底层优化简述:

1. 引入AST抽象语法树:PHP5.6直接从语法分析生成OPCODE,PHP7先生成AST再编译成OPCODE,解耦语法解析和编译,为后续优化打下基础

2. 内存管理优化:重新设计zval结构,从堆分配改为大部分栈分配,减少内存分配释放开销,内存占用降低30-50%

3. 函数调用优化:优化传参机制,减少调用栈开销,内部函数调用性能提升明显

4. HashTable重构:数组底层HashTable的键值对从单独分配改为连续存储,提升缓存命中率和遍历性能

5. 新增类型声明:标量类型声明(int/float/string/bool)和返回值类型声明,严格模式下编译期类型检查,减少运行时类型判断开销

6. 错误处理重构:引入Throwable接口,把致命错误改成可捕获的Error异常,不再直接崩溃

实际效果:PHP7比PHP5.6性能提升约2倍,内存占用降低约一半。

二、升级兼容性问题及解决:

1. mysql扩展彻底移除:旧mysql_*系列函数全部移除,封装数据库适配层统一改成mysqli或PDO,先封装再逐步替换

2. PHP4风格构造函数废弃:类名同名构造函数废弃,全局替换成__construct()

3. ereg正则扩展移除:ereg_*改成preg_*(PCRE),注意正则语法差异

4. mcrypt扩展在PHP7.1移除:mcrypt_encrypt改成openssl_encrypt,注意算法和填充方式对应

5. 其他:list()不再支持字符串键、foreach内部指针行为变化等,通过单元测试和回归测试覆盖

升级流程:

静态扫描(PHP7 -l语法检查+PHP_CodeSniffer兼容性规则)→测试环境完整回归→按模块灰度上线→错误日志监控→出问题快速回滚。

部署步骤

    1. 在测试环境完成全部验证
    2. 备份生产环境代码和数据库
    3. 在维护窗口期执行升级
    4. 切换 Web 服务器 PHP 模块
    5. 验证 phpinfo() 确认版本正确
    6. 监控应用日志和错误日志
    7. 如遇问题,准备回滚方案

总结

方面

关键要点

升级策略

逐级升级(5.6→7.0→7.1→7.2),切勿跳升

代码兼容

关注 gettype()、is_object()、数组/对象转换、废弃函数(create_function、__autoload)

扩展更新

mysql→mysqli/PDO,mcrypt→OpenSSL/Sodium,ereg→preg

配置调整

更新 php.ini 路径,移除废弃指令,调整 pcre.recursion_limit

性能优化

启用 OPcache,合理配置内存和缓存参数

测试部署

渐进测试、独立环境验证、准备回滚方案

 

PHP7底层优化详细解析:

PHP7 的四大底层优化可以概括为一句话:

l AST 解决了编译器的可维护性和优化入口问题;

l 用 zval 重构消灭了标量变量的堆分配和引用计数;

l 用 HashTable 连续存储解决了数组的碎片化和缓存问题;

l 再用类型声明把错误前移。

 

逐个拆解:每个优化到底解决了什么问题

① AST 抽象语法树 —— 解决 "编译器不可维护、优化无从下手"

PHP5 的问题:词法、语法分析之后直接生成 opcode,中间没有任何表示层。

后果有两个:

编译器代码充满语法糖特判—— 像 foreach、list、array() 这类语法,都需要在生成 opcode 时写一堆特殊逻辑打补丁,代码难维护、难加新语法;

优化无处安放—— 很多优化(常量折叠、冗余消除)需要在 "代码结构" 层面做,而 opcode 是扁平指令流,丢失了语法结构信息,想优化只能针对 opcode 打补丁,非常脆弱。

PHP7 的方案:插入 AST 作为中间层。

语法分析产出的是树形结构,完整保留了 "这段代码是什么表达式、什么语句" 的信息。

编译优化可以在 AST 上安全地做(比如 2 * 3 在编译期直接折叠成 6),编译器的每个环节也各自独立、可单独测试。

收益:编译更快、编译器代码量显著下降、静态分析工具(如 IDE、代码规范工具)有了统一的解析基础 —— 这是 "一次重构,长期受益" 的典型。

 

② zval 重构 + 栈分配 —— 解决 "内存分配与引用计数开销"

PHP5 的问题:PHP 里每个变量的值都装在一个叫 zval 的结构体里,而这个结构体自带引用计数,且大多在堆上分配。于是:

每写一个变量、传一个参数、返回一个值,都可能触发堆分配;

每次赋值 / 传参都要维护 refcount 的增减(写时复制 COW),这是 PHP5 最著名的性能瓶颈之一;

zval 结构大(64 位下约 24 字节),还要间接寻址一层指针。

PHP7 的方案:重构 zval,把它缩到 16 字节,并做了一次关键的分层 ——

标量(int /double/bool /null)直接内联在 zval 里,不再堆分配、不再有引用计数;

引用计数只保留在真正需要共享的容器上:字符串 zend_string、数组 zend_array、引用;

大量临时变量和局部变量改在执行栈帧上分配,用完即走。

收益:普通标量操作基本实现 "零分配、零引用计数",内存占用整体下降约 50%,执行速度大幅提升。这也解释了为什么 PHP7 在纯计算密集的循环里提速尤其明显。

 

③ HashTable 重构 —— 解决 "数组底层碎片化、缓存不友好"

PHP5 的问题:PHP 数组的底层是 HashTable,而 HashTable 的每个元素(bucket)是链表节点 + 各自独立 malloc。后果:

插入 N 个元素要分配 N 块小内存,内存碎片严重;

遍历时指针在内存里跳来跳去,CPU 缓存命中率极低—— 现代 CPU 性能很大程度上靠缓存,这在当时是很大的浪费。

PHP7 的方案:把存储模型改成分离式 ——

元素数据连续存放在一块 arData 数组里(按插入顺序),哈希索引单独用一张 uint32 索引表指向数据槽;

整数连续键直接退化为 packed array:不用哈希,直接用数组下标,速度接近 C 数组;

只有真正的字符串键才走哈希计算。

收益:一次大块分配代替 N 次小分配;顺序遍历完全命中缓存;数组遍历、查找、插入普遍快 2–3 倍。因为 PHP 里数组几乎无处不在(请求参数、配置、结果集……),这一项是 PHP7 全局提速的最大功臣之一。

 

④ 标量类型声明 —— 解决 "类型错误被静默吞掉、接口无契约"

PHP5 的问题:类型提示只支持类、接口、array、callable,不支持 int / float / string / bool。弱类型下,"abc" + 1、把字符串当数字传参这类错误不会被报错,而是被隐式转换静默吞掉,等到线上出 bug 时往往很难定位。

PHP7 的方案:

支持标量类型声明(参数 + 返回值);

引入 declare(strict_types=1) 严格模式:类型不匹配直接抛 TypeError,不做任何隐式转换;

PHP 7.1 补上 ?Type 可空类型和 void 返回类型。

收益(要点要说全):

正确性:错误从 "运行深处" 提前到 "调用边界",立刻暴露;

可维护性:函数签名即文档,接口契约明确;

为优化铺路:类型已知后,引擎在运行时可省去部分动态类型判断 —— 这条在 PHP7 阶段主要是 "铺垫",真正的 JIT 收益要到 PHP8 才兑现,这一点值得明确,不要夸大 PHP7 类型声明的性能收益。

 

 

 

posted @ 2021-02-03 15:15  阿陌i  阅读(287)  评论(0)    收藏  举报