Go para desenvolvedores PHP: o que muda na prática
1. Paradigmas e Filosofia de Linguagem
A primeira diferença que um desenvolvedor PHP encontra ao migrar para Go é o sistema de tipos. Enquanto PHP é dinamicamente tipado (você pode fazer $x = "texto" e depois $x = 42 sem problemas), Go exige que você declare o tipo de cada variável. Isso parece restritivo no início, mas elimina uma classe inteira de bugs em tempo de compilação.
// PHP — tipagem dinâmica
$nome = "João";
$nome = 123; // Funciona, mas pode causar bugs
// Go — tipagem estática
var nome string = "João"
nome = 123 // Erro de compilação: cannot use 123 (type int) as type string
Em vez de classes e herança, Go usa structs e interfaces. A composição substitui a herança:
// PHP — orientação a objetos clássica
class Animal {
public function falar() { return "som"; }
}
class Cachorro extends Animal {
public function falar() { return "latido"; }
}
// Go — composição com structs e interfaces
type Animal interface {
Falar() string
}
type Cachorro struct{}
func (c Cachorro) Falar() string { return "latido" }
Go não possui exceptions. O tratamento de erros é explícito com o tipo error:
// PHP — try-catch
try {
$arquivo = fopen("dados.txt", "r");
} catch (Exception $e) {
echo "Erro: " . $e->getMessage();
}
// Go — tratamento explícito
arquivo, err := os.Open("dados.txt")
if err != nil {
fmt.Println("Erro:", err)
return
}
2. Sintaxe e Estruturas de Controle
A declaração de variáveis em Go usa := para inferência de tipo, enquanto PHP usa $:
// PHP
$nome = "Maria";
$idade = 30;
// Go
nome := "Maria"
idade := 30
// Ou explicitamente:
var nome string = "Maria"
Go tem apenas uma estrutura de repetição: o for. Mas ele se adapta a diferentes usos:
// PHP — foreach, while, for
foreach ($itens as $item) { }
while ($condicao) { }
for ($i = 0; $i < 10; $i++) { }
// Go — apenas for
for _, item := range itens { }
for condicao { } // equivalente ao while
for i := 0; i < 10; i++ { }
Funções em Go podem retornar múltiplos valores, algo que no PHP exigiria arrays ou objetos:
// PHP — retorno único
function dividir($a, $b) {
if ($b == 0) return ["erro" => "divisão por zero"];
return ["resultado" => $a / $b];
}
// Go — múltiplos retornos
func dividir(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("divisão por zero")
}
return a / b, nil
}
3. Gerenciamento de Dependências e Módulos
Go usa Go Modules (go.mod e go.sum), que funcionam de forma similar ao Composer do PHP, mas com diferenças importantes:
// PHP — composer.json
{
"require": {
"monolog/monolog": "^2.0"
}
}
// Go — go.mod
module meu-projeto
go 1.21
require github.com/gorilla/mux v1.8.0
Enquanto PHP usa use com namespaces relativos, Go importa pacotes com caminhos absolutos baseados em URL:
// PHP
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// Go
import (
"log"
"net/http"
"github.com/gorilla/mux"
)
Go não tem autoloading. O código é compilado estaticamente em um único binário, o que elimina a necessidade de carregar classes sob demanda.
4. Concorrência e Paralelismo
Esta é uma das maiores diferenças. PHP tradicionalmente executa código de forma síncrona (cada requisição é um processo separado). Go tem goroutines e canais como cidadãos de primeira classe:
// PHP — sem concorrência real (a menos que use pthreads)
$dados = [];
foreach ($urls as $url) {
$dados[] = file_get_contents($url); // bloqueante
}
// Go — concorrência com goroutines e canais
func buscar(url string, ch chan<- string) {
resp, _ := http.Get(url)
ch <- resp.Status
}
func main() {
ch := make(chan string)
urls := []string{"https://exemplo1.com", "https://exemplo2.com"}
for _, url := range urls {
go buscar(url, ch) // executa em paralelo
}
for range urls {
fmt.Println(<-ch) // recebe resultados
}
}
Para sincronização, Go oferece sync.WaitGroup e o poderoso select:
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Println("Trabalhando:", id)
}(i)
}
wg.Wait() // aguarda todas as goroutines
5. Tratamento de Erros e Logging
O padrão if err != nil é onipresente em Go. Diferente do PHP, onde exceptions podem ser capturadas em qualquer nível, Go exige que cada erro seja tratado explicitamente:
// PHP — exception pode ser capturada longe do local de origem
function conectar() {
throw new Exception("Falha na conexão");
}
try {
conectar();
} catch (Exception $e) {
log($e->getMessage());
}
// Go — erro tratado imediatamente
func conectar() (string, error) {
return "", errors.New("falha na conexão")
}
resultado, err := conectar()
if err != nil {
log.Printf("Erro: %v", err)
return
}
Go permite wrapping de erros para adicionar contexto, sem hierarquia de classes:
if err != nil {
return fmt.Errorf("falha ao processar usuário %d: %w", id, err)
}
Para logging, o pacote nativo log é simples, mas funcional. Não há equivalente ao Monolog com múltiplos handlers, mas bibliotecas como logrus ou zap preenchem essa lacuna.
6. Performance e Compilação
Go compila para binário nativo. Um programa Go é um único executável que não depende de runtime externo:
# PHP — precisa de servidor + interpretador
php -S localhost:8080 index.php
# Go — compila e executa diretamente
go build -o meuapp main.go
./meuapp
O garbage collector de Go é mais agressivo que o do PHP, mas com pausas muito curtas. Ferramentas de profiling são nativas:
// Ativar profiling no Go
import _ "net/http/pprof"
// Acessar: http://localhost:6060/debug/pprof/
Enquanto PHP depende de Xdebug ou Blackfire, Go oferece pprof integrado, flame graphs e análise de alocação.
7. Ecossistema e Ferramentas para Web
Go tem um servidor HTTP nativo no pacote net/http, sem necessidade de SAPI como PHP-FPM:
// PHP — precisa de Nginx + PHP-FPM
// index.php
echo "Olá, mundo!";
// Go — servidor nativo
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Olá, mundo!")
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
Para roteamento, bibliotecas como chi ou gorilla/mux substituem frameworks PHP:
// Go com chi
r := chi.NewRouter()
r.Get("/usuarios/{id}", buscarUsuario)
r.Post("/usuarios", criarUsuario)
http.ListenAndServe(":8080", r)
Em vez de Eloquent ou Doctrine, Go usa database/sql com drivers SQL puros. Bibliotecas como sqlx adicionam conveniência:
// Go com database/sql
db, _ := sql.Open("postgres", "conn_string")
rows, _ := db.Query("SELECT id, nome FROM usuarios")
for rows.Next() {
var u Usuario
rows.Scan(&u.ID, &u.Nome)
}
8. Migração Prática: Projeto Real
Vamos replicar um CRUD simples de PHP para Go:
Estrutura de pastas em Go:
meu-crud/
├── main.go
├── handlers/
│ └── usuario.go
├── models/
│ └── usuario.go
├── database/
│ └── conexao.go
└── go.mod
Testes unitários em Go vs PHP:
// PHP — PHPUnit
class UsuarioTest extends TestCase {
public function testCriar() {
$this->assertTrue(true);
}
}
// Go — testing package
func TestCriarUsuario(t *testing.T) {
resultado := criarUsuario("João")
if resultado == nil {
t.Error("Esperava um usuário, recebi nil")
}
}
Deploy:
- PHP: Container + PHP-FPM + Nginx (múltiplos componentes)
- Go: Binário único + container mínimo (scratch image)
# Dockerfile para Go
FROM golang:1.21 AS build
WORKDIR /app
COPY . .
RUN go build -o meuapp
FROM scratch
COPY --from=build /app/meuapp /meuapp
CMD ["/meuapp"]
Conclusão
Migrar de PHP para Go exige repensar a forma como você estrutura código, trata erros e gerencia concorrência. A tipagem estática e o tratamento explícito de erros trazem mais segurança em tempo de compilação, enquanto goroutines e canais abrem possibilidades de concorrência que o PHP tradicional não oferece. O ecossistema Go é mais enxuto, mas extremamente poderoso para aplicações que exigem performance e simplicidade operacional.
Referências
- Documentação oficial da linguagem Go — Guia completo de sintaxe, pacotes e ferramentas da linguagem
- Go by Example — Tutoriais práticos com exemplos de código para cada conceito do Go
- How to Write Go Code — Documentação oficial sobre organização de módulos e pacotes
- Understanding Go's Garbage Collector — Explicação detalhada sobre o funcionamento do GC em Go
- Go Web Examples — Tutoriais práticos de desenvolvimento web com Go, incluindo roteamento e middlewares
- PHP to Go Migration Guide — Guia prático de migração com comparações de código entre as duas linguagens
- Effective Go — Melhores práticas e padrões de código recomendados pela equipe do Go