Коротко: Go — компилируемый язык со статической типизацией, горутинами и одним бинарником; синтаксически проще PHP, но заставляет иначе думать об ошибках и параллелизме.
Если вы пишете на PHP и присматриваетесь к Go, короткий ответ такой: Go — компилируемый язык со статической типизацией, встроенной конкурентностью (горутины) и одним самодостаточным бинарником на выходе. Синтаксис у него проще, чем у PHP, но он заставляет иначе думать об ошибках, типах и параллелизме. Ниже разберём главные отличия, покажем код и дадим практический путь старта.
Чем Go отличается от PHP
Самое важное, что стоит принять на старте, — это не «другой синтаксис», а другая модель выполнения и мышления:
- Компиляция в бинарник. Нет интерпретатора и PHP-FPM:
go buildдаёт один исполняемый файл, который просто запускается на сервере. Деплой — это «положить бинарник». - Статическая строгая типизация. Типы проверяются на этапе компиляции, и часть ошибок ловится ещё до запуска, а не в проде.
- Конкурентность «из коробки». Горутины и каналы вместо отдельных процессов или внешних очередей для параллельных задач.
- Нет классов и наследования. Вместо них — структуры, методы и интерфейсы. В основе лежит композиция, а не иерархии.
- Ошибки — это значения. По умолчанию никаких исключений: функция возвращает
error, и вы обрабатываете его явно. - Минимализм и единообразие. Один официальный форматтер (
gofmt), маленькая спецификация языка, мало «магии» и неявного поведения.
Первая программа и модули
Go-проект начинается с модуля — это аналог composer.json. Инициализация и «hello world»:
go mod init example.com/hello
// main.go
package main
import "fmt"
func main() {
fmt.Println("Привет, Go!")
}
Запуск — go run ., сборка — go build. Зависимости подтягиваются автоматически в go.mod и go.sum (аналоги composer.json и composer.lock). Команда go mod tidy наводит порядок: добавляет недостающие и убирает лишние зависимости.
Базовые типы, слайсы и мапы
Вместо привычного PHP-массива «на все случаи жизни» в Go есть отдельные структуры данных. Чаще всего вы будете работать со слайсами (динамические массивы) и мапами (ассоциативные массивы):
nums := []int{1, 2, 3} // слайс
nums = append(nums, 4) // добавление элемента
ages := map[string]int{ // мапа (ключ -> значение)
"Лео": 36,
}
ages["Иван"] = 28
for key, value := range ages {
fmt.Println(key, value)
}
Важное отличие от PHP: типы элементов фиксированы. В []int нельзя случайно положить строку — компилятор не даст.
Структуры, методы и интерфейсы вместо классов
В Go нет классов. Данные описываются структурами, поведение — методами, а контракты — интерфейсами:
type User struct {
Name string
Age int
}
func (u User) Greeting() string {
return "Привет, " + u.Name
}
type Greeter interface {
Greeting() string
}
Главная особенность — интерфейсы в Go неявные: тип реализует интерфейс автоматически, если у него есть нужные методы. Никакого implements не нужно. Это располагает к маленьким интерфейсам и композиции вместо громоздких иерархий наследования, к которым привыкаешь в PHP.
Горутины и каналы: главная фишка
То, ради чего часто и приходят в Go. Горутина — это очень лёгкий поток, запускается ключевым словом go. Каналы (chan) — безопасный способ обмена данными между горутинами:
func main() {
ch := make(chan string)
go func() {
ch <- "готово" // пишем в канал
}()
fmt.Println(<-ch) // читаем из канала (блокируется, пока не появится значение)
}
Когда горутин много и нужно дождаться их всех, помогает sync.WaitGroup:
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
fmt.Println("задача", n)
}(i)
}
wg.Wait() // ждём завершения всех
Там, где в PHP вы бы вынесли задачу в очередь (RabbitMQ или Kafka), в Go часто достаточно горутин и каналов внутри одного процесса. Это не отменяет очереди для распределённых систем, но для параллелизма в рамках сервиса инструмент встроенный.
Обработка ошибок без исключений
Go возвращает ошибку как обычное значение, и вы проверяете её явно сразу после вызова:
data, err := os.ReadFile("config.json")
if err != nil {
return fmt.Errorf("не смог прочитать конфиг: %w", err)
}
// здесь data гарантированно валидна
Глагол %w «оборачивает» исходную ошибку, сохраняя цепочку причин — потом её можно разобрать через errors.Is и errors.As. После try/catch это сначала кажется многословным, но делает поток ошибок видимым и предсказуемым. Механизмы panic и recover тоже есть, но это для действительно исключительных ситуаций, а не для бизнес-логики.
Тестирование из коробки
Тесты — часть языка, отдельный фреймворк не нужен. Идиоматичный стиль — table-driven тесты:
func TestSum(t *testing.T) {
cases := []struct {
a, b, want int
}{
{1, 2, 3},
{0, 0, 0},
{-1, 1, 0},
}
for _, c := range cases {
if got := Sum(c.a, c.b); got != c.want {
t.Errorf("Sum(%d,%d)=%d, хотели %d", c.a, c.b, got, c.want)
}
}
}
Запуск — go test ./.... Покрытие — go test -cover.
Сборка и деплой одним бинарником
Главный практический плюс для эксплуатации: на выходе один файл без зависимостей рантайма. Типовой multi-stage Dockerfile получается крошечным:
FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app ./cmd/server
FROM alpine:3.20
COPY --from=build /app /app
ENTRYPOINT ["/app"]
Итоговый образ — единицы мегабайт, а не сотни, как с полноценным PHP-окружением.
Когда Go, а когда PHP
- Go хорош, когда нужны высокая конкурентность, низкое потребление памяти, сетевые сервисы и демоны, CLI-утилиты, самодостаточные бинарники.
- PHP остаётся сильнее там, где зрелая экосистема веб-фреймворков (Symfony, Laravel), быстрый CRUD, админки, контент-сайты и большой пул библиотек под типовые задачи.
На практике это часто гибрид: основной продукт на PHP, а «горячие» по нагрузке части — на Go.
С чего начать PHP-разработчику
- Пройдите интерактивный A Tour of Go — за вечер получите базу синтаксиса.
- Перепишите маленькую утилиту, которую обычно делаете на PHP CLI (парсер файла, скрипт-обработчик).
- Освойте горутины и каналы на простой задаче — например, параллельные HTTP-запросы с агрегацией результата.
- Напишите небольшой HTTP-сервис на стандартном
net/http— сначала без фреймворка, чтобы понять основы. - Закройте его table-driven тестами и соберите в Docker одним бинарником.
Go не заменяет PHP, а дополняет его там, где нужны конкурентность и лёгкие сервисы. Если думаете, где Go уместен именно в вашем проекте, а где лучше остаться на PHP — это как раз тема для консультации.


Комментарии