【PHPエンジニア視点】GoとPHPを比較して学ぶGoの基本と強み

## はじめに
社内でのポジションはフロントエンドエンジニアとして働いております。
今までメインで使用していた言語はPHPなので、自分に馴染みのあるPHPと比較してGoを理解して行こうと思います。
今回紹介する内容は初学者向けですが、改めて違いを知りたい方や経験者まで幅広い方に読んでいただければ幸いです。


#### 言語の概要

| 項目 | Go | PHP |
| --- | --- | --- |
| 用途 | サーバー・ネットワーク・クラウド系システム | 主にWebアプリケーション |
| 実行形式 | コンパイル型（バイナリ生成、あらかじめプログラム全体を機械語に翻訳してから実行する方式） | インタプリタ型（スクリプト実行、プログラムを1行ずつその場で解釈しながら実行する方式） |
| 並行処理 | goroutine（ゴルーチン）を使った軽量スレッドで高速な並行処理が可能 | 並行処理は得意ではない（マルチスレッドのサポートは限定的） |
| パフォーマンス | 高速（Cに近い） | Web用途には十分だがGoほど高速ではない |
| 記述スタイル | 静的型付け、構文はシンプルでCライク | 動的型付け、HTMLと混ぜて書ける（テンプレート的な使い方） |
| 標準ライブラリ | ネットワーク・並行処理が強力 | Web向け機能が豊富（フォーム処理、データベース操作など） |
| フレームワーク | 標準のライブラリ重視でフレームワークなしでも開発可能 | Laravel、Symfonyなど強力なWebフレームワークが存在 |

#### なぜGoは処理が高速なの？
1. ネイティブコードにコンパイルされる
・Goはコンパイル型言語で、ソースコードは機械語（バイナリ）に直接変換される
・実行時のオーバーヘッドが少なく、C言語に近い性能を発揮する

2. ガーベジコレクタが高速で効率的
・GoのGCは低レイテンシ・並列対応で、プログラムの停止時間が非常に短い
・メモリ管理の負荷が少ないため、高速な処理が可能

3. 軽量な並行処理（goroutine）
・goroutineは数KBのスタックサイズで動作し、スレッドより軽量
・数千〜数万の処理を同時に並行させても、コストが非常に低い




## 挙動の違い
何もかも違う言語ですが具体的にどんな違いがあるかを見ていきます。

まずは変数と型で比較します。
 
【Go】
```
package main

import "fmt"

func main() {
    var name string = "Go"
    age := 30 // 型推論される（int）
    fmt.Println(name, age)
}
```

【PHP】
```
<?php

$name = "PHP";
$age = 30; // 動的型付け
echo "$name $age\n";
```
- Goは型は明示 or 推論されるが固定される
- PHPは実行時に型が決まる
<br>

次に構造体（Go）とクラス（PHP）の比較
<br>

【Go】（構造体＋メソッド）
```
type User struct {
    Name string
}

func (u User) Greet() string {
    return "Hello, " + u.Name
}
```

【PHP】（クラス＋メソッド）
```
class User {
    public string $name;

    public function __construct(string $name) {
        $this->name = $name;
    }

    public function greet(): string {
        return "Hello, " . $this->name;
    }
}
```
- Goはstruct（構造体） + メソッド（関数）で「オブジェクトっぽい」設計を作る（純粋なOOPではない）
- PHPはオブジェクト指向でクラスや継承が基本


<br>
エラーハンドリングGoのerror型、PHPの例外を比較
<br>

【Go】
```
func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}
```

【PHP】
```
function divide(int $a, int $b): int {
    if ($b === 0) {
        throw new Exception("division by zero");
    }
    return intdiv($a, $b);
}
```
- Goは戻り値でエラーを返す（明示的なエラーチェック）
- PHPは例外を使う（例外で処理が飛ぶ）


## Go特有の機能
#### Goroutine（ゴルーチン）

- Goroutine（ゴルーチン）とは、Go言語で並行処理を実現するための非常に軽量な実行単位（軽量スレッド）

- goキーワードを使って関数や処理を並行して実行でき、通常のスレッドよりも少ないメモリやリソースで多数同時に動かすことできる。
(goキーワード：Go言語の予約語のひとつで、関数やメソッドを「並行して（goroutineとして）」実行するために使う特別な命令)
- Goランタイムが管理し、複雑なスレッド制御を意識せず簡単に並行処理を記述できるのが特徴
(Goランタイム：Goのプログラムがコンピュータ上で動くために必要な機能（メモリ管理、並行処理など）を提供する土台となる部分)
- PHPにはこのような構文レベルの並行処理はない(拡張を使えば可能だけど標準ではない）

```
package main
import (
    "fmt"
    "time"
)
func sayHello() {
    fmt.Println("Hello goroutine!")
}
func main() {
    go sayHello() // ゴルーチンで非同期実行
    time.Sleep(1 * time.Second) // メインが先に終わらないように一時停止
    fmt.Println("Main function done.")
}
```

例として以下のような場面で使用されます。
- ネットワークリクエスト、ファイル操作、DBアクセス
- 画像処理、数値計算など（並列化による効率化）
- 非同期イベント処理、GUIイベント、システムイベントの処理
- 非同期メッセージ処理、メッセージキューからのメッセージ処理など

#### チャネル
複数のゴルーチンが安全にデータをやり取りするために使う機能
```
package main

import (
    "fmt"
)

func main() {
    // チャネルを作る（int型の値を送受信できる）
    ch := make(chan int)

    // ゴルーチンで別の処理を実行
    go func() {
        fmt.Println("ゴルーチン：値を送ります")
        ch <- 42 // チャネルに値を送る(sender)
    }()

    // メインルーチンでチャネルから値を受け取る(receiver)
    value := <-ch
    fmt.Println("メインルーチン：受け取った値 =", value)
}
```
- チャネルは「送信が完了するまで、受信側が待つ」「受信側が準備できていなければ、送信もブロックされる」＝ 同期的な通信になる
  - なので同じデータを同時に複数の処理が触らないようにする制御を書かなくても、ゴルーチン間で安全にデータを渡せる


#### defer（後で実行）

処理を「関数終了時に自動実行」できるのがdefer
```
package main
import "fmt"
func main() {
    defer fmt.Println("後で実行されるよ！")
    fmt.Println("先に実行されるよ！")
}
```
- phpにもregister_shutdown_function()という似たような構文はあるがdeferほど直感的ではない
- Goのdeferは、より関数に密着したリソース管理と後処理の仕組みであり、スコープが明確かつ直感的であり、エラー処理との連携もスムーズ。一方、PHPのregister_shutdown_function()は、スクリプト全体の終了処理を目的とした機能。
- Goのdeferは、複雑な関数でリソース漏れを防ぎ、コードを信頼できて読みやすくする

<br>
例として以下のような場面で使用されます。

- ファイルやリソースのクローズ
- エラーが発生した場合でも、必ず実行する必要がある処理を行う場合
- 関数の終了処理、ログの記録など


<br>

**複数deferがあるとどうなる?**

Goのdeferは複数あると「後入れ先出し（LIFO）」の順で実行されます、つまり最後に書いたdeferが最初に実行されるということです。
deferは関数の終了直前に実行される処理を予約し、複数ある場合はスタック構造のように後から追加した順に実行されます。

```
package main

import "fmt"

func main() {
    defer fmt.Println("defer 1")
    defer fmt.Println("defer 2")
    defer fmt.Println("defer 3")

    fmt.Println("main end")
}
```



出力結果
```
main end
defer 3
defer 2
defer 1
```

## Goを触ってみた感想
- PHPにない機能や概念が諸々あってキャッチアップが楽しい
- 個人的にdeferはfinallyを便利にしたものというように感じた
- フレームワークなしでも開発可能なのが良い、フレームワーク固有の機能を把握する手間が省けるし管理もシンプルになる
- 標準ライブラリが充実してる
- 型がガチガチに決まってるので曖昧な挙動も少なく安心できる

今回まだキャッチアップし始めでメモリ管理や並列処理など慣れない感覚は色々ありますがGoの強みとポテンシャルを感じました。知れば知るほど楽しい言語だと思います。
#
プロダクトに向き合い、ユーザーとつながる開発を。
ネットネイティブでは、そんなエンジニアを歓迎しています
https://www.wantedly.com/companies/mdpr