不知不觉间,通过公司内部转岗的机会,已经接触 Go 这门语言快五个月了,期间大大小小写了几个应用(公司项目目前是一个项目多个应用的模式,未使用到微服务架构),也已积累了大量 CURD 经验。这里就列举部分 Go 与 PHP 的不同之处,希望能给计划转 Go 或者才刚入门的小伙伴一点帮助,如果其中有讲的不对的地方,还请大家能够多多包涵,尽量喷得轻一些,谢谢~

首先 Go 是一门编译型的语言,不同于 PHP 解释型语言的特性,它的变量类型是声明时就得指定的,这点 PHP 7 也加入了声明时指定类型的语法,但是并不强制,所以它俩还是有一些开发上的区别。最典型能够拿出来说的,就是 PHP 的 array ,用过的人都知道,PHP array 的键限定了 int 跟 string,但是它的值可以包罗万象,往里面丢什么都可以,并且保持一定的顺序;而 Go 中的 array 是定长的,而且一开始声明了类型,只能往它里面塞同类型的数据。Go 中的 slice 弥补了 array 定长的特点,可以后期动态扩容,但是它的键只能是 int ,并且从 0 开始一路往下累加,虽然可以从中剔除出一些元素,但也不是特别方便。而 Go 中的 map 就比较灵活,它的键除了 func、map、slice 等类型不能指定,其他都可以直接声明,所以在日常的开发中,我觉得 map 的使用频率可能会比 slice 还高。

但 Go 的 map 也不是万能的,首先他不像 PHP 的 array 那样便捷,值可以把所有类型都丢进去;其次它的数据在 for range (Go中循环遍历 array、slice、map、chan 等等类型的方式)中是无序的,你在定义的时候按顺序一个个声明,但在循环中每次执行都是不同的遍历结果,这点虽然可以用 slice 组合使用来解决,但也不能像 PHP 的 array 那样优雅的处理数据,所以还是比较蛋疼的,只想说 PHP 的 array 真是 yyds。

另一个比较会让人在意的点,就是 Go 的错误或者说异常处理方式,是通过函数/方法的最后一个返回值来返回,调用方接收了之后进行自定义处理。这样虽然也比较灵活,可以基于实现 error 接口进行灵活声明各种意义上的错误/异常,也可以通过 errors.New(msg string) 的形式直接抛出一个错误/异常,但还是比不上 PHP 的 try...catch... 来的优雅并且处理方式更灵活,有时候你写的逻辑中会大量充斥着这种代码:

if err != nil {
    // ...
} 

虽然这跟语言的定位有很大关系,Go 主张一切显式传递,包括函数的传参不能设置默认值,函数的执行结果跟异常都得通过返回值的形式传递,这些都是 Go 一开始就定义好的语言特性,我们虽然有时候会觉得很无语,但还是得尊重。

众所周知,Go 最大的特性就是底层支持并发处理,而它的并发处理所依靠的,就是 Goroutine ,也就是协程;而在它的底层实现中,又有 GPM 这样强大的调度模型,这是其他语言无法比拟的,所以它能最大程度利用硬件内核的性能达到效果,这是它的优势;同时它又有 chan 这种专门用来处理协程间通信的数据结构,并且语言上支持 select 监听 chan 的数据变动而做出处理的这么一个结构,使得它非常适合用来处理耗时任务、异步任务等需求。

我们知道,PHP 常规的运行模式为 PHP-FPM ,底层其实是用进程去处理每个请求,因为进程的特性而可以做到上下文隔离的这么一个状态,开发非常方便,全局数组拿来即用也不需要关心数据污染的情况。然而缺点也是很明显的,这样就导致执行效率很低,每次处理一个请求就得挂载资源释放资源,非常浪费硬件性能;虽然 PHP 7.4 增加了 opcache 并且 PHP 8.0 进一步增加了 JIT 特性,优化了执行效率,但是根本问题还是没有得到解决,所以这也是 PHP 一直在国内不受待见的原因,再加上生态链这些年一直都没怎么壮大(Laravel 其实做了很多),这才导致 PHP 即将跌出 TIOBE 编程语言排行榜前十的地位,隐隐显现出即将被排第十一的 Go 取代的这么一个现象。

但是 PHP 国内还有一种使用方式,那就是 Swoole,还有近些年开始流行起来的 Swow(作者一开始是一个大学生,年轻有为),也用 C / C++ 实现了协程功能,并且也引入了 Go 中 chan 跟 defer 的概念,在性能上已经不亚于 Go 的 Goroutine,甚至于 Swoole 的协程是基于进程内切换的这么一个特性,所以它不像 Go 那样需要用到锁去解决并发安全问题,心智负担更小。然后基于 Swoole / Swow 搭建的框架比如 imi、Hyperf 等,已经在生态链的完善这一点做的很好了(扩展了微服务、gRPC、分布式事务等功能),一般公司的生产项目还是可以使用它们进行开发运营。

目前来看,两门语言各自都有发展,PHP 最新版本已经迭代到 8.2 了,而其中 8.1 新加的枚举特性,Go 中还没有这种数据结构,目前来说还是很有发展前景的,并且 PHP 也向着强类型语言的特点去努力了,最新的 8.2 中已废弃对象的动态属性这一使用方式,越来越讲究语言的严谨性,在开发时出错的概率进一步在降低。而 Go 1.18 中加入了泛型这么一个特性,虽然复杂度直线上升,但也还是提高了语言的灵活度,为 Go 的发展迈出了重大的一步;还有 Go 1.20 据说将整体 CPU 性能提高了 2%,构建速度相比之前提升了 10%,也还是挺有活力的。

对我来说,目前公司项目使用的是 Go ,我也会一直用 Go 去开发去实践去进阶,但是我想说我做不到过河拆桥这种事,我是从 PHPer 一路走过来的,我不会放弃当初学习 PHP 的那种心态,始终保持一颗敬畏的心去对待它,我也不会抛弃这门语言,日常工作如果有用到 PHP 的地方,我还是不遗余力的去用它完成任务,同时也时刻保持关注 PHP 的动态,期待它的再次崛起!