链接???? http://tigerb.cn/php2go/
前言
整理了一份简要的手册,帮助大家高效的上手Go语言,主要是通过对比PHP和Go的不同点来强化理解,内容主要分为以下四部分:
语言层面差异
基础语法差异
避坑指南
进阶使用
语言层面差异
备注:下文基于PHP主流php-fpm模式。
对比项 | PHP | Go |
---|---|---|
字符串表示 | 单引号(PSR) | 双引号 |
拼接字符串 | . | + |
语言版本兼容性 | 不好 | 向下兼容 |
代码风格 | 无官方标准,社区标准起步晚 | 自始至今官方统一标准,且提供工具 |
脚本语言 | 是 | 不是 |
强类型语言 | 不是(PHP7支持严格模式) | 是 |
是否支持垃圾回收 | 是 | 是 |
面向对象语言(OOP) | 神似 | 部分支持,核心是合成复用 |
是否支持继承 | 是 | 否(有合成复用) |
是否支持interface | 是 | 是 |
是否支持try...catch... | 是 | 否 |
是否支持包管理 | 是 | 是 |
是否支持跨平台 | 是 | 是 |
环境搭建成本 | 高 | 低 |
执行方式 | cli命令行模式、php-fpm模式(①) | 二进制 |
进程模型 | 多进程 | 单进程 |
原生是否支持创建TCP/UDP服务 | 是(支持不好,生产不可用) | 是 |
原生是否支持创建HTTP服务 | 是(支持不好,生产不可用) | 是 |
进程阻塞性 | 是 | 否 |
是否支持协程 | 否(②) | 是 |
并发能力(③) | 弱 | 极强 |
是否常驻内存运行 | 不是(④) | 是 |
引入文件方式 | require 或者include 对应文件 |
import 导入包 |
是否支持单元测试 | 是 | 是 |
是否支持基准测试(benchmark) | 否 | 是 |
是否支持性能分析 | 支持(xhprof/tideways) | 支持(pprof/dlv) |
性能分析工具使用成本 | 高(装扩展成本高) | 极低 |
①其他模式还有swoole等
②PHP的swoole协程框架等支持协程
③此处不考虑I/O多路复用,PHP的swoole协程框架等也支持协程并发
④PHP的swoole协程框架是常驻内存,cli命令行模式也可以常驻内存等
刚开始由PHP语言转Go语言的过程,重点是编程意识的转变,尤其是以下几点:
强类型
常驻内存运行
理解和使用指针
并发安全
资源及时释放或返还
基础语法差异
备注:下文基于PHP5.4+版本
常用基本类型对比
PHP类型比较少和简单,PHP常用数据类型有boolean布尔值、string字符串、int整型、float浮点型、array数组、object对象。
PHP常用数据类型和Go语言对应或者类似的类型做个对比,如下:
语言\类型 | boolean | string | int | float | array | object |
---|---|---|---|---|---|---|
PHP | bool | string | int | float | array(1,2,3)索引数组、array('1' => 1, '2' => 2, '3' => 3)关联数组 | 实例化类class |
Go | bool | string | int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64 | float32、float64 | [length]type | 比较像struct |
除此之外Go还支持更丰富的类型:
类型 |
---|
slice切片(相当于PHP的索引数组) |
map(相当于PHP的关联数组) |
channel(管道,通过通信共享,不要通过共享来通信) |
指针(Go语言的值类型都有对应的指针类型) |
byte(字节,对应uint8别名,可以表示Ascaii码) |
rune(对应int32,可以表示unicode) |
等等 |
自定义类型,例如type userDefinedType int32 |
常用基本类型初始化方式对比
类型 | PHP | Go(定义变量带var 关键字,或者不带直接使用语法糖:= ) |
---|---|---|
boolean | $varStr = true; |
var varStr bool = true 或者 var varStr = true 或者 varStr := true |
string | $varStr = 'demo'; |
var varStr string = "" 或者 varStr := "" (:=写法下面省略) |
int32 | $varNum = 0; |
var varInt32 int32 = 0 |
int64 | 同上 | var varInt64 int64 = 0 |
float32 | $varNum = 0.01; |
var varFloat32 float32 = 0 |
float64 | 同上 | var varFloat64 float64 = 0 |
array | $varArray = array(); 或者语法糖 $varArray = []; |
var varArray [6]int32 = [6]int32{} |
slice(切片) | 同上,PHP叫索引数据 | var varSlice []int32 = []int32{} 切片相对于数据会自动扩容 |
map | $varMap = array('key' => 'value'); |
var varMap map[string]int32 = map[string]int32{} |
closure(闭包) | $varClosure = function() {}; |
var varClosure func() = func() {} |
channel | 无 | var varChannel chan string = make(chan string) 无缓存channel;var varChannelBuffer chan string = make(chan string, 6) 有缓存channel |
PHP类的实例化和Go结构体的初始化的对比
PHP类的实例化
/*
定义class
*/
class ClassDemo {
// 私有属性
private $privateVar = "";
// 公有属性
public $publicVar = "";
// 构造函数
public function __construct()
{
// 实例化类时执行
}
// 私有方法
private function privateFun()
{
}
// 公有方法
public function publicFun()
{
}
}
// 实例化类ClassDemo 获取类ClassDemo的对象
$varObject = new ClassDemo(); // 对象(类)
Go结构体的初始化
// 包初始化时执行
func init() {
}
type StructDemo struct{
// 小写开头驼峰表示私有属性
// 不可导出
privateVar string
// 大写开头驼峰表示公有属性
// 可导出
PublicVar string
}
// 小写开头驼峰表示私有方法
// 结构体StructDemo的私有方法
func (demo *StructDemo) privateFun() error {
return nil
}
// 大写开头驼峰表示公有属性
// 结构体StructDemo的公有方法
func (demo *StructDemo) PublicFun() error {
return nil
}
// 初始化结构体StructDemo
// structDemo := &StructDemo{}
常用函数对比
常用函数描述 | PHP | Go |
---|---|---|
数组长度 | count() | len() |
分割字符串为数组 | explode() | strings.Split(s string, sep string) []string |
转大写 | strtoupper() | strings.ToUpper(s string) string |
转小写 | strtolower() | strings.ToLower(s string) string |
去除空格 | trim() | strings.Trim(s, cutset string) string |
json序列化 | json_encode() | json.Marshal(v interface{}) ([]byte, error) |
json反序列化 | json_decode() | json.Unmarshal(data []byte, v interface{}) error |
序列化(不再建议使用) | serialize()、unserialize() | 包https://github.com/wulijun/go-php-serialize |
md5 | md5() | 包crypto/md5 |
终端输出 | echo、var_dump等 | fmt.Println(a ...interface{}) |
各种类型互转 | intval()等 | 包strconv |
避坑指南
谨慎使用全局变量,全局变量不会像PHP一样,在完成一次请求之后被销毁
形参是slice、map类型的参数,注意值可被全局修改
资源使用完毕,记得释放资源或回收资源
不要依赖map遍历的顺序
不要并发写map
注意判断指针类型不为空nil,再操作
Go语言不支持继承,但是有合成复用
1. 谨慎使用全局变量,全局变量不会像PHP一样,在完成一次请求之后被销毁
package main
import (
"github.com/gin-gonic/gin"
)
// 全局变量不会像PHP一样,在完成一次请求之后被销毁
var GlobalVarDemo int32 = 0
// 模拟接口逻辑
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
atomic.AddInt32(&GlobalVarDemo,1)
c.JSON(200, gin.H{
"message": GlobalVarDemo,
})
})
r.Run()
}
// 我们多次请求接口,可以很明显发现:全局变量不会像PHP一样,在完成一次请求之后被销毁。
// 但是PHP不一样,全局变量在完成一次请求之后会被自动销毁。
// curl "127.0.0.1:8080/ping"
// {"message":1}
// curl "127.0.0.1:8080/ping"
// {"message":2} <------- 值在递增
// curl "127.0.0.1:8080/ping"
// {"message":3} <------- 值在递增