PHP开发者转Go需摒弃PHP思维惯性:不用$_GET、不自动类型转换、不依赖include拼凑逻辑、不默认处理HTTP生命周期;应从net/http+fmt入手,定义结构体而非滥用map[string]interface{},避免php2go等不可维护工具。

php 开发者转 golang,不是“学完语法就能写”,而是得绕开 PHP 思维惯性,直接对标 Go 的实际使用方式。你不需要从零重学编程,但必须接受:Go 没有 $_GET、不自动类型转换、不靠 include 拼凑逻辑、也不默认帮你处理 HTTP 请求生命周期。
先别碰框架,从 net/http + fmt 写起
PHP 开发者习惯用 Laravel/Swoole 封装好的路由、中间件、请求对象;但 Go 里这些是可选的,net/http 包本身已足够跑通完整 Web 流程。过早上 gin 或 echo 容易掩盖底层机制,导致你写不出符合 Go 风格的错误处理或中间件。
- 用
http.HandleFunc替代$_SERVER['REQUEST_URI']判断路径 - 用
r.Method和r.URL.Query().Get("id")替代$_GET,别再写parse_str(file_get_contents("php://input")) - 所有 HTTP 响应必须显式写
w.WriteHeader(200)或http.Error(w, "xxx", 400),没有“默认 200”
interface{} 不是 $data,map[string]interface{} 更不是万能容器
PHP 里 $user = ["name" => "Tom", "age" => 25] 可以一路 json_encode、foreach、isset;但在 Go 里,这种松散结构会立刻暴露问题:
-
map[string]interface{}无法直接用.Name访问字段,必须类型断言:if name, ok := data["name"].(string); ok { ... } - JSON 解码到
interface{}后,数字默认是float64,不是int—— 这会导致数据库写入失败或比较出错 - 真正该做的是定义结构体:
type User struct { Name string `json:"name"` Age int `json:"age"` },然后json.Unmarshal(b, &u)
别信“自动转换工具”,php2go 生成的代码基本不可维护
已有项目里搜到的 php2go 或 gophp 工具,确实能把 for($i=0; $i 翻成 <code>for i := 0; i ,但它们完全无法处理:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- PHP 的动态函数调用(
$func = "get_{$type}"; $func())→ Go 没有等价机制,得用switch或映射表 -
__autoload/composer autoload→ Go 没有运行时加载,包依赖在编译期就锁定 - 超全局变量(
$_SESSION,$_COOKIE)→ Go 里要自己解析、加密、存储,没现成替代 - 错误处理:PHP 的
try/catch被转成 Go 的if err != nil,但工具不会帮你把嵌套 5 层的catch拆成清晰的错误传播链
真正卡住人的不是语法,是 Go 的“默认约束”
PHP 允许你忽略很多事:连接不关、错误不判、变量不声明类型、函数返回值不检查;Go 编译器强制你面对所有这些。
立即学习“PHP免费学习笔记(深入)”;
-
os.Open必须defer f.Close(),否则文件句柄泄漏 —— PHP 的fopen在脚本结束时自动释放,这个习惯在 Go 里会直接压垮服务 -
database/sql查询后必须rows.Close(),不然连接池耗尽,错误信息是"sql: connection pool exhausted",和 SQL 本身无关 - 并发场景下,
for range循环中启动 goroutine 时,闭包捕获的是循环变量地址,不是值 —— 这种 bug 在 PHP 里不存在,但 Go 里一写就错


















