您的位置:首页 > 编程语言 > PHP开发

问世 20 多年的 PHP 还是最好的编程语言吗?

2018-01-20 00:00 751 查看
点击上方“CSDN”,选择“置顶公众号”关键时刻,第一时间送达!作者简介:Panda,一个热爱技术,喜欢刨根问底,热爱分享, 热爱开源的程序猿,活跃于开源社区,乐于分享交流。PHP 开源项目贡献者,对网络安全、PHP 内核、Nginx 内核、MySQL 有一些研究。本文来自作者在 GitChat 上分享 「2017 年 PHP 社区总结,2018 PHP 发展展望」主题内容。

一、2017 PHP 社区总结:回顾 PHP 语言本身的升级和变化首先一起回顾下 PHP 的发展史:PHP 作为 Web 开发领域性价比最高的语言,已经问世 20 多年了。

注:一个 Web 站点可以会使用多种语言作为它的开发语言,本文含有不少从鸟哥 PPT 里的截图,图片版权归鸟哥所有。
PHP 开始于 1994 年,最初产生于 Rasmus Lerdorf 的一个简单的想法,当时 Rasmus 用 C 语言写了一个应用程序,这个程序就是用来追踪和维护自己的个人主页的。
并且 Rasmus 对其又进行了扩展,使其可以应用于 web 表单还可以和数据库进行交互。就这样 PHP 的第一个版本就诞生了。Rasmus 称其为 “Personal Home Page/Forms Interpreter” 简称 PHP/FI。
用 Rasmus 自己的话说:起初并不想开发一门新的编程语言,但是随着 PHP/FI 的发展,渐渐的就不再受他的控制了。就这样一个开发团队行程了,并且在 1997 年的 11 月发布了第二个版本 PHP/FI 2。
再往后,Zeev Suraski 和 Andi Gutmans 两个人的出现,更是使得 PHP 的发展走向了一个新的里程碑。1997 年,两人重新写了 PHP 的解释器,形成了 PHP 的第三个版本 PHP3,也就是在此时正式名字由 PHP/FI 改为 PHP(Hypertext Preprocessor 超文本预处理器)。时隔一年,两人在 1998 年又重新写了 PHP 的核心代码,用了将近一年的时间,Zend 引擎在 1999 年诞生了。接着在 2000 年 5 月,带有第一代 zend 引擎的 PHP4 正式发布了。随后其发展进入了一个平缓的阶段,带有第一代 Zend 引擎的 PHP4 在 2008 年 8 月达到 4.4.9 以后就再没有进行后续开发,也没有任何的安全更新。我用的最早的一个 PHP4 的程序应该是 DEDECMS 了。这时 PHP 还是面向过程的编程方式。
在 2004 年 6 月份的时候,PHP 的发展到达了第二个里程碑。带有 Zend Engine II 的 PHP5 正式发布,在这 PHP5 中开始支持面向对象,而且性能明显增强。直到 2008 年很多程序都不再支持 PHP4 版本了,取而代之的是 PHP5。接着,下一个人物该出场了,他的出现使 PHP 从 5 又上升了一格成为了 PHP6。他的名字叫 Andrei Zmievski。当时 PHP5 发布以后,PHP 收到了各种各样的反馈,反馈的内容就是在 PHP 中缺少编码转换的支持。所以在 2005 年的时候,由 Andrei 领导在 PHP 中嵌入了 ICU 库。并且使文本字符串以 unicode-16 的方式呈现。这一举动,对于 PHP 本身以及用户的编码方式都产生了大的改变,所以 PHP6 应运而生了。虽说这一改变跨越很大,但是由于开发人员不能很好的理解所做的这些改变,并且向 unicode-16 编码(这一编码方式在 web 环境中很少被用到)转换会导致性能的下降,种种原因导致这一工程停滞下来。而且在 2009 年发布的 PHP5.3 还有 2010 年发布的 5.4 几乎涵盖了所有从 PHP6 移植来的功能。因此在 2010 年这项工程停止了,直到 2014 年也没有被人们所接受。在 2014-2015 年期间,PHP7 正式发布了。最初对于 PHP7 的这个版本是存在一些争议的,因为先前的 PHP6 并没有正式发布,就夭折了,所以直接到 7 这个版本并不是很合适。但是在一些学术论文还有书籍中已经引用了 PHP6 这个名称,所以说最终人们将其定位 7。对于 PHP7 其主要的目标就是通过重构 Zend 引擎,使 PHP 的性能更加的优化,同时保留语言的兼容性。由于是对其引擎的重构,因此 PHP7 的引擎目前已是第三代 Zend Engine 3。
今天 PHP7 已经正式发布,纵观其从诞生到发展壮大,有成功也有失败,而今天的成功又仅仅源于昨天的一个简单的想法。作为一名程序员,如果自己在现在的一个想法,多少年后也能产生如此大的成就,那岂是一个 “自豪” 所能表达的。类似的情况也发生在另一个人的身上,linux 的奠基者 linus。不管怎么说,作为一名 PHP 程序员,看到 PHP 今天的成绩自然感到高兴,自己也会在 PHP 的路上一直走下去,希望 PHP 的发展越来越好。1.PHP 7.0 的优化标量类型和返回类型声明(Scalar Type Declarations & Scalar Type Declarations);
更多的 Error 变为可捕获的 Exception;
AST(Abstract Syntax Tree,抽象语法树);
Native TLS(Native Thread local storage,原生线程本地存储);
Zval 的改变。
PHP 的各种类型的变量,其实,真正存储的载体就是 Zval,它特点是海纳百川,有容乃大。从本质上看,它是 C 语言实现的一个结构体(struct)。对于写 PHP 的同学,可以将它粗略理解为是一个类似 array 数组的东西。PHP5 的 Zval,内存占据 24 个字节:

PHP7 的 Zval,内存占据 16 个字节:

Zval 从 24 个字节下降到 16 个字节,为什么会下降呢?这里需要补一点点的 C 语言基础,辅助不熟悉 C 的同学理解。struct 和 union(联合体)有点不同,Struct 的每一个成员变量要各自占据一块独立的内存空间,而 union 里的成员变量是共用一块内存空间。也就是说修改其中一个成员变量,公有空间就被修改了,其他成员变量的记录也就没有了。因此,虽然成员变量看起来多了不少,但是实际占据的内存空间却下降了。除此之外,还有被明显改变的特性,部分简单类型不再使用引用。Zval 结构图:

图中 Zval 的由 2 个 64bits(1 字节 =8bit,bit 是 “位”)组成,如果变量类型是 long、bealoon 这些长度不超过 64bit 的,则直接存储到 value 中,就没有下面的引用了。当变量类型是 array、objec、string 等超过 64bit 的,value 存储的就是一个指针,指向真实的存储结构地址。对于简单的变量类型来说,Zval 的存储变得非常简单和高效。不需要引用的类型:NULL、Boolean、Long、Double;需要引用的类型:String、Array、Object、Resource、Reference。(1)内部类型 zend_stringZend_string 是实际存储字符串的结构体,实际的内容会存储在 val(char,字符型)中,而 val 是一个 char 数组,长度为 1,方便成员变量占位)。

结构体最后一个成员变量采用 char 数组,而不是使用 char*,这里有一个小优化技巧,可以降低 CPU 的 cache miss。如果使用 char 数组,当 malloc 申请上述结构体内存,是申请在同一片区域的,通常是长度是 sizeof(_zend_string) + 实际 char 存储空间。但是,如果使用 char*,那个这个位置存储的只是一个指针,真实的存储又在另外一片独立的内存区域内。使用 char[1] 和 char* 的内存分配对比:

从逻辑实现的角度来看,两者其实也没有多大区别,效果很类似。而实际上,当这些内存块被载入到 CPU 的中,就显得非常不一样。前者因为是连续分配在一起的同一块内存,在 CPU 读取时,通常都可以一同获得(因为会在同一级缓存中)。而后者,因为是两块内存的数据,CPU 读取第一块内存的时候,很可能第二块内存数据不在同一级缓存中,使 CPU 不得不往 L2(二级缓存)以下寻找,甚至到内存区域查到想要的第二块内存数据。这里就会引起 CPU Cache Miss,而两者的耗时最高可以相差 100 倍。另外,在字符串复制的时候,采用引用赋值,zend_string 可以避免的内存拷贝。(2)PHP 数组的变化(HashTable 和 Zend Array)在编写 PHP 程序过程中,使用最频繁的类型莫过于数组,PHP5 的数组采用 HashTable 实现。如果用比较粗略的概括方式来说,它算是一个支持双向链表的 HashTable,不仅支持通过数组的 key 来做 hash 映射访问元素,也能通过 foreach 以访问双向链表的方式遍历数组元素。

这个图看起来很复杂,各种指针跳来跳去,当我们通过 key 值访问一个元素内容的时候,有时需要 3 次的指针跳跃才能找对需要的内容。而最重要的一点,就在于这些数组元素存储,都是分散在各个不同的内存区域的。同理可得,在 CPU 读取的时候,因为它们就很可能不在同一级缓存中,会导致 CPU 不得不到下级缓存甚至内存区域查找,也就是引起 CPU 缓存命中下降,进而增加更多的耗时。PHP7 的 Zend Array:

新版本的数组结构,非常简洁,让人眼前一亮。最大的特点是,整块的数组元素和 hash 映射表全部连接在一起,被分配在同一块内存内。如果是遍历一个整型的简单类型数组,效率会非常快,因为,数组元素(Bucket)本身是连续分配在同一块内存里,并且,数组元素的 zval 会把整型元素存储在内部,也不再有指针外链,全部数据都存储在当前内存区域内。当然,最重要的是,它能够避免 CPU Cache Miss(CPU 缓存命中率下降)。Zend Array 的变化:数组的 value 默认为 zval。
HashTable 的大小从 72 下降到 56 字节,减少 22%。
Buckets 的大小从 72 下降到 32 字节,减少 50%。
数组元素的 Buckets 的内存空间是一同分配的。
数组元素的 key(Bucket.key)指向 zend_string。
数组元素的 value 被嵌入到 Bucket 中。
降低 CPU Cache Miss。
(3)函数调用机制(Function Calling Convention)PHP7 改进了函数的调用机制,通过优化参数传递的环节,减少了一些指令,提高执行效率。PHP5 的函数调用机制:

图中,在 vm 栈中的指令 send_val 和 recv 参数的指令是相同,PHP7 通过减少这两条重复,来达到对函数调用机制的底层优化。PHP7 的函数调用机制:

通过宏定义和内联函数(inline),让编译器提前完成部分工作 C 语言的宏定义会被在预处理阶段(编译阶段)执行,提前将部分工作完成,无需在程序运行时分配内存。能够实现类似函数的功能,却没有函数调用的压栈、弹栈开销,效率会比较高。内联函数也类似,在预处理阶段,将程序中的函数替换为函数体,真实运行的程序执行到这里,就不会产生函数调用的开销。PHP7 在这方面做了不少的优化,将不少需要在运行阶段要执行的工作,放到了编译阶段。例如参数类型的判断(Parameters Parsing),因为这里涉及的都是固定的字符常量。因此,可以放到到编译阶段来完成,进而提升后续的执行效率。例如下图中处理传递参数类型的方式,从左边的写法,优化为右边宏的写法。

2. PHP7.1 的优化可空类型:主要用于参数类型声明和函数返回值声明;
list 的方括号简写: 我们知道在 PHP5.4 之前只能通过 array() 来定义数组,5.4 之后添加了 [] 的简化写法;
允许在 list 中指定 key;
void 返回类型:PHP7.0 添加了指定函数返回类型的特性,但是返回类型却不能指定为 void,7.1 的这个特性算是一个补充;
类常量属性设定;
多条件 catch;
详见 RFC 地址。
3. PHP7.2 的变化语法、函数方面更严格了,性能也有提升。详见 PHP 7 ChangeLog:https://wiki.php.net/rfc/deprecations_php_7_2。
PHP 的性能演进 (从 PHP5.0 到 PHP7.1 的性能全评测):http://www.laruence.com/2016/12/18/3137.html。
PHP 周边优秀开源项目1. 框架篇目前最火热的 Laravel 类似 ROR 的语法,具有丰富的组件、活跃的社区、更多的语法糖;
然后就是由华人开发的 Yii 框架,Gii 生成代码;
还有国产的 ThinkPHP 快速上手;
还有 codeigniter 简洁方便,还有 Phalcon 是用 C 语言开发的框架,以 PHP 拓展的形式,性能强悍、功能强大。
2. 组件篇国产的 Swoole 重新定义 PHP,异步、高性能;
国产的 SeasLog  C 拓展高性能的 Log 组件;
在此强烈推荐大家看看 Symfony 这个框架解耦做到极致 , 每个模块都是一个组件 , 都可以单独拿出来使用;
大家应该会和微信开发打交道 强烈推荐 EasyWeChat 封装适度、简洁的 API ;
PHP-ml 是 PHP 的机器学习库,同时包含算法、交叉验证、神经网络、预处理、特征提取等。
3. 工具篇推荐 Composer,优秀的 PHP 包管理工具 , 有了它 , 你就可以把社区优秀的开源组件为自己所用;
Psysh,这是我经常使用的,调试验证小段代码信手拈来 !


Xdebug 断点调试利器 , 让 BUG 无处可逃;
Xhprof 专注于性能分析 , 找出你代码慢在哪里 , 持续优化  持续提高性能;
Deployer 项目部署工具 简单 快捷 ;
Piplint 新鲜出炉的  项目部署系统  国产  中文文档支持 ;
更多有趣的 PHP 组件可以关注这个项目 awesome-php。
4. 项目篇Fecshop :基于 PHP Yii2 框架开发的一款优秀的开源电商系统,可持续发展的电商系统;
zentaopms :国内市场市场占有率最高的项目管理 BUG 管理软件;
OpenCart :国外电商适用的开源电商系统。
PHP 在 Web 生态中的变化一句话总结 PHP 在 Web 生态中的变化:更快更高更强。更快: 从 php5.6 到 php7.0 从 7.0 到 7.1 从 7.1 到 7.2 持续的让内核性能提高  压榨每一个字节  优化每一行代码;
更高:从 DedeCMS  帝国 CMS Discuz 老牌的 Web 系统  到现在的组件化   抽象程度更高了;
更强:从经典的 Web 开发  到现在 PHP-ML 机器学习  UI 桌面软件开发   PHP 更强了。
国内的 PHP 社区Laravel-Chain:不仅仅是 Laravel;
SF:有技术问题可以去提问;
V2EX:一个小而美的社区。
二、2018PHP 发展展望PHP 周边生态的发力编程语言最重要的生态,社区活跃则语言繁荣,社区衰落则语言式微,就好比水与鱼的关系。正在开发中的 libpkd => 拓展语言原生能力,构建运行时标准库,目前已经基于 Swoole 生态涌出很多优秀的框架。swoft-cloud 崭露头角的 PHP 微服务框架,可能是 PHP 社区的 Spring-Cloud;
SwooleDistributedSwooleDistributed 是一款 PHP 结合 swoole 扩展开发的开源高性能的服务器框架。 Swoole 打造底层基石 ,SD 构建上层应用 完美结合。
PHP 程序猿的努力随着开源的流行 越来越多的 PHPer 在贡献自己的一份力量  GitHub 上 PHP 的开源项目越来越多,例如 packagist 上的组件越来越丰富,而且 PHP 语言本身的性能也在不断提升,让 PHP 语言换发出新的生命力。参考资料PHP:https://secure.php.net/manual/zh/index.php
技术行者:http://hansionxu.blog.163.com/
风雪之隅:http://www.laruence.com/
声明:封面图为付费下载自视觉中国。
————— 推荐阅读 —————点击图片即可阅读








内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: