Skip to content

PHP 开发者学习 Go 指南

如果你熟悉 PHP 和 Web 开发,这份指南将帮助你快速上手 Go 语言。

快速对比表

特性PHPGo
类型系统动态类型静态类型
执行方式解释执行编译执行
包管理ComposerGo Modules
Web 框架Laravel/Symfony/ThinkPHPZoox
数组关联数组/索引数组数组/切片/Map
错误处理Exception显式错误返回
并发多进程/多线程Goroutine
部署需要 PHP-FPM/Web 服务器单一可执行文件

概念映射

变量和类型

PHP:

php
<?php
// 动态类型
$name = "Alice";
$age = 30;
$price = 19.99;

// 类型提示(PHP 7+)
function greet(string $name): string {
    return "Hello, " . $name;
}

Go:

go
// 静态类型
var name string = "Alice"
age := 30
price := 19.99

// 函数签名
func greet(name string) string {
    return "Hello, " + name
}

关键差异:

  • Go 是静态类型,编译时检查
  • Go 使用 := 进行短变量声明
  • Go 的类型系统更严格

数组和关联数组

PHP:

php
// 索引数组
$numbers = [1, 2, 3, 4, 5];

// 关联数组
$person = [
    'name' => 'Alice',
    'age' => 30
];

// 数组操作
$doubled = array_map(function($n) {
    return $n * 2;
}, $numbers);

Go:

go
// 数组(固定长度)
var numbers [5]int = [5]int{1, 2, 3, 4, 5}

// 切片(动态数组)
slice := []int{1, 2, 3, 4, 5}

// Map(关联数组)
person := map[string]interface{}{
    "name": "Alice",
    "age":  30,
}

// 数组操作(需要手动实现)
var doubled []int
for _, n := range slice {
    doubled = append(doubled, n*2)
}

关键差异:

  • Go 区分数组、切片和 Map
  • PHP 的数组是混合类型,Go 需要明确类型
  • Go 没有内置的 array_map/filter,需要手动实现

类和结构体

PHP:

php
class Person {
    private $name;
    private $age;
    
    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
    
    public function greet() {
        return "Hello, I'm " . $this->name;
    }
}

$person = new Person("Alice", 30);

Go:

go
type Person struct {
    name string
    age  int
}

func NewPerson(name string, age int) *Person {
    return &Person{name: name, age: age}
}

func (p *Person) Greet() string {
    return "Hello, I'm " + p.name
}

person := NewPerson("Alice", 30)

关键差异:

  • Go 使用结构体而不是类
  • Go 没有构造函数,使用工厂函数
  • Go 没有继承,使用组合

错误处理

PHP:

php
try {
    $data = file_get_contents('file.txt');
    if ($data === false) {
        throw new Exception('文件读取失败');
    }
    // 处理数据
} catch (Exception $e) {
    echo "错误: " . $e->getMessage();
}

Go:

go
data, err := os.ReadFile("file.txt")
if err != nil {
    return fmt.Errorf("文件读取失败: %w", err)
}
// 处理数据

关键差异:

  • Go 不使用异常,使用显式错误返回
  • Go 的错误处理是函数签名的一部分
  • Go 要求显式检查每个错误

Web 开发

PHP (Laravel):

php
// routes/web.php
Route::get('/users/{id}', function ($id) {
    $user = User::find($id);
    if (!$user) {
        return response()->json(['error' => '用户不存在'], 404);
    }
    return response()->json($user);
});

PHP (ThinkPHP):

php
// application/index/controller/User.php
namespace app\index\controller;

class User
{
    public function index($id)
    {
        $user = \app\index\model\User::get($id);
        if (!$user) {
            return json(['error' => '用户不存在'], 404);
        }
        return json($user);
    }
}

Go (Zoox):

go
// main.go
app := zoox.New()

app.Get("/users/:id", func(c *zoox.Context) {
    id := c.Param("id")
    user, err := getUser(id)
    if err != nil {
        c.JSON(404, zoox.H{"error": "用户不存在"})
        return
    }
    c.JSON(200, user)
})

关键差异:

  • Go 的框架更轻量
  • Go 的错误处理是显式的
  • Go 的性能通常更好

快速上手路径

第 1 步:理解类型系统(2-3 天)

从动态类型到静态类型是最大的挑战:

  1. 类型声明 - 所有变量都需要类型
  2. 类型转换 - 需要显式转换
  3. 类型推断 - 使用 := 简化声明

重点章节:

第 2 步:学习编译和部署(1-2 天)

PHP 是解释型,Go 是编译型:

  1. 编译 - go build 生成可执行文件
  2. 部署 - 单一可执行文件,不需要运行时
  3. 交叉编译 - 可以编译到不同平台

重点章节:

第 3 步:掌握 Web 框架(2-3 天)

使用 Zoox 框架,类似 Laravel/Symfony/ThinkPHP,但更简单:

  1. 路由 - 类似 Laravel/ThinkPHP 路由
  2. 中间件 - 类似 Laravel/ThinkPHP 中间件
  3. 错误处理 - 显式错误返回

重点章节:

第 4 步:学习并发编程(3-5 天)

PHP 主要使用多进程,Go 使用 Goroutine:

  1. Goroutine - 轻量级线程
  2. Channel - 用于通信
  3. 并发模式 - Worker Pool 等

重点章节:

代码对比示例

数组操作

PHP:

php
$numbers = [1, 2, 3, 4, 5];

// Map
$doubled = array_map(function($n) {
    return $n * 2;
}, $numbers);

// Filter
$evens = array_filter($numbers, function($n) {
    return $n % 2 === 0;
});

// Reduce
$sum = array_reduce($numbers, function($carry, $n) {
    return $carry + $n;
}, 0);

Go:

go
numbers := []int{1, 2, 3, 4, 5}

// Map
doubled := make([]int, len(numbers))
for i, n := range numbers {
    doubled[i] = n * 2
}

// Filter
var evens []int
for _, n := range numbers {
    if n%2 == 0 {
        evens = append(evens, n)
    }
}

// Reduce
sum := 0
for _, n := range numbers {
    sum += n
}

数据库操作

PHP (PDO):

php
try {
    $pdo = new PDO("mysql:host=localhost;dbname=test", $user, $pass);
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->execute([$id]);
    $user = $stmt->fetch(PDO::FETCH_ASSOC);
    return $user;
} catch (PDOException $e) {
    throw new Exception("数据库错误: " . $e->getMessage());
}

Go (database/sql):

go
db, err := sql.Open("mysql", "user:pass@/test")
if err != nil {
    return nil, fmt.Errorf("连接数据库失败: %w", err)
}
defer db.Close()

var user User
err = db.QueryRow("SELECT * FROM users WHERE id = ?", id).Scan(&user.ID, &user.Name)
if err != nil {
    return nil, fmt.Errorf("查询失败: %w", err)
}

return &user, nil

JSON 处理

PHP:

php
// 编码
$person = ['name' => 'Alice', 'age' => 30];
$json = json_encode($person);

// 解码
$data = json_decode($json, true);
$name = $data['name'];

Go:

go
// 编码
person := map[string]interface{}{
    "name": "Alice",
    "age":  30,
}
jsonData, err := json.Marshal(person)

// 解码
var data map[string]interface{}
err := json.Unmarshal(jsonData, &data)
name := data["name"].(string)

常见陷阱

1. 类型转换习惯

PHP 自动转换:

php
$result = "5" + 3;  // 8

Go 需要显式转换:

go
// 错误
result := "5" + 3

// 正确
result := "5" + strconv.Itoa(3)
// 或者
num, _ := strconv.Atoi("5")
result := num + 3

2. 数组和切片混淆

PHP 数组是动态的:

php
$arr = [];
$arr[] = 1;
$arr[] = 2;

Go 区分数组和切片:

go
// 数组(固定长度)
var arr [2]int
arr[0] = 1
arr[1] = 2

// 切片(动态)
var slice []int
slice = append(slice, 1)
slice = append(slice, 2)

3. 错误处理方式

PHP 使用异常:

php
try {
    $data = fetchData();
} catch (Exception $e) {
    // 处理错误
}

Go 使用显式错误返回:

go
data, err := fetchData()
if err != nil {
    // 处理错误
    return err
}

4. 并发编程概念

PHP 主要使用多进程:

php
$pid = pcntl_fork();
if ($pid == 0) {
    // 子进程
} else {
    // 父进程
}

Go 使用 Goroutine:

go
go func() {
    // 并发执行
}()

学习建议

  1. 适应静态类型:这是最大的挑战,需要时间适应
  2. 理解编译过程:Go 是编译型语言,部署方式不同
  3. 学习并发编程:PHP 的并发模型与 Go 完全不同
  4. 利用 Web 开发经验:你的 PHP Web 开发经验很有用

推荐学习顺序

  1. Go 语言简介 - 理解编译型语言
  2. 基础语法 - 重点学习类型系统
  3. 函数和方法 - 注意多返回值
  4. 数据结构 - 理解数组、切片、Map
  5. 接口和类型 - 类似 PHP 的接口
  6. 错误处理 - 适应新的错误处理方式
  7. 并发编程 - 重点学习
  8. 包和模块 - 类似 Composer
  9. 实战项目 - Web API 开发

下一步

现在你已经了解了从 PHP 到 Go 的转换要点,建议:

  1. 重点学习类型系统 - 这是最大的差异
  2. 适应错误处理方式 - 从异常到显式错误返回
  3. 学习并发编程 - PHP 的并发模型与 Go 完全不同
  4. 完成 Web 项目 - 利用你的 Web 开发经验

祝你学习愉快!

基于 VitePress 构建