diff --git a/docs/pt-br/CONTRIBUTING.md b/docs/pt-br/CONTRIBUTING.md
index fb2f74e0..7183424d 100644
--- a/docs/pt-br/CONTRIBUTING.md
+++ b/docs/pt-br/CONTRIBUTING.md
@@ -33,8 +33,8 @@ Adicione diretórios ao `.dockerignore`.
### Sem Docker (Linux e macOS)
-[Siga as instruções para compilar a partir dos fontes](compile.md) e passe a
-flag de configuração `--debug`.
+[Siga as instruções para compilar a partir do código-fonte](compile.md) e passe
+a flag de configuração `--debug`.
## Executando a suite de testes
@@ -199,7 +199,7 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push
- [PHP embedding in Go (go-php)](https://github.com/deuill/go-php)
- [PHP embedding in Go (GoEmPHP)](https://github.com/mikespook/goemphp)
- [PHP embedding in C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
-- [Extending and Embedding PHP por Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
+- [Extending and Embedding PHP, por Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
- [What the heck is TSRMLS_CC, anyway?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
- [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
diff --git a/docs/pt-br/README.md b/docs/pt-br/README.md
index b0db439a..bb8533fc 100644
--- a/docs/pt-br/README.md
+++ b/docs/pt-br/README.md
@@ -1,14 +1,14 @@
-# FrankenPHP: Servidor de aplicações moderno para PHP
+# FrankenPHP: um moderno servidor de aplicações para PHP

-O FrankenPHP é um servidor de aplicações moderno para PHP, construído sobre o
+O FrankenPHP é um moderno servidor de aplicações para PHP, construído sobre o
servidor web [Caddy](https://caddyserver.com/).
-O FrankenPHP oferece superpoderes às suas aplicações PHP graças aos seus
-recursos impressionantes: [_Early Hints_](early-hints.md),
-[modo worker](worker.md), [recursos em tempo real](mercure.md), suporte
-automático a HTTPS, HTTP/2 e HTTP/3...
+O FrankenPHP dá superpoderes às suas aplicações PHP graças aos seus recursos
+impressionantes: [_Early Hints_](early-hints.md), [modo worker](worker.md),
+[recursos em tempo real](mercure.md), suporte automático a HTTPS, HTTP/2 e
+HTTP/3...
O FrankenPHP funciona com qualquer aplicação PHP e torna seus projetos Laravel e
Symfony mais rápidos do que nunca, graças às suas integrações oficiais com o
@@ -56,7 +56,7 @@ frankenphp php-cli /caminho/para/seu/script.php
### Docker
-Alternativamente, [imagens do Docker](docker.md) estão disponíveis:
+Alternativamente, [imagens Docker](docker.md) estão disponíveis:
```console
docker run -v .:/app/public \
@@ -94,11 +94,12 @@ frankenphp php-server
## Documentação
- [Modo clássico](classic.md)
-- [Modo Worker](worker.md)
+- [Modo worker](worker.md)
- [Suporte a Early Hints (código de status HTTP 103)](early-hints.md)
- [Tempo real](mercure.md)
- [Servindo grandes arquivos estáticos com eficiência](x-sendfile.md)
- [Configuração](config.md)
+- [Escrevendo extensões PHP em Go](extensions.md)
- [Imagens Docker](docker.md)
- [Implantação em produção](production.md)
- [Otimização de desempenho](performance.md)
@@ -109,7 +110,7 @@ frankenphp php-server
- [Integração com Laravel](laravel.md)
- [Problemas conhecidos](known-issues.md)
- [Aplicação de demonstração (Symfony) e benchmarks](https://github.com/dunglas/frankenphp-demo)
-- [Documentação da biblioteca Go](https://pkg.go.dev/github.com/dunglas/frankenphp)
+- [Documentação da biblioteca Go](https://pkg.go.dev/github.com/php/frankenphp)
- [Contribuindo e depurando](CONTRIBUTING.md)
## Exemplos e esqueletos
diff --git a/docs/pt-br/classic.md b/docs/pt-br/classic.md
index bab35f85..e41c27d2 100644
--- a/docs/pt-br/classic.md
+++ b/docs/pt-br/classic.md
@@ -18,9 +18,9 @@ semelhante ao modo dinâmico do PHP-FPM.
As conexões enfileiradas aguardarão indefinidamente até que uma thread PHP
esteja disponível para servi-las.
Para evitar isso, você pode usar a
-[configuração](config.md#configuracao-do-caddyfile) `max_wait_time` para limitar
-o tempo que uma requisição pode esperar por uma thread PHP livre antes de ser
-rejeitada.
+[configuração](config.md#configuracao-do-caddyfile) `max_wait_time` na
+configuração global do FrankenPHP para limitar o tempo que uma requisição pode
+esperar por uma thread PHP livre antes de ser rejeitada.
Além disso, você pode definir um
[tempo limite de escrita razoável no Caddy](https://caddyserver.com/docs/caddyfile/options#timeouts).
diff --git a/docs/pt-br/compile.md b/docs/pt-br/compile.md
index 52bb7c15..194d41d9 100644
--- a/docs/pt-br/compile.md
+++ b/docs/pt-br/compile.md
@@ -1,4 +1,4 @@
-# Compilar a partir dos fontes
+# Compilar a partir do código-fonte
Este documento explica como criar um binário FrankenPHP que carregará o PHP como
uma biblioteca dinâmica.
@@ -29,10 +29,10 @@ brew link --overwrite --force shivammathur/php/php-zts
### Compilando o PHP
-Alternativamente, você pode compilar o PHP a partir dos códigos-fonte com as
+Alternativamente, você pode compilar o PHP a partir do código-fonte com as
opções necessárias para o FrankenPHP seguindo estes passos.
-Primeiro, [obtenha os códigos-fonte do PHP](https://www.php.net/downloads.php) e
+Primeiro, [obtenha o código-fonte do PHP](https://www.php.net/downloads.php) e
extraia-os:
```console
@@ -91,10 +91,10 @@ devem ser instaladas.
Alternativamente, esses recursos podem ser desabilitados passando as tags de
compilação para o compilador Go.
-| Recurso | Dependência | Tag de compilação para desabilitá-lo |
-|----------------------------------------|-----------------------------------------------------------------------|--------------------------------------|
-| Compressão Brotli | [Brotli](https://github.com/google/brotli) | `nobrotli` |
-| Reiniciar workers ao alterar o arquivo | [Watcher C](https://github.com/e-dant/watcher/tree/release/watcher-c) | `nowatcher` |
+| Recurso | Dependência | Tag de compilação para desabilitá-lo |
+|---------------------------------------|-----------------------------------------------------------------------|--------------------------------------|
+| Compressão Brotli | [Brotli](https://github.com/google/brotli) | `nobrotli` |
+| Reiniciar workers ao alterar arquivos | [Watcher C](https://github.com/e-dant/watcher/tree/release/watcher-c) | `nowatcher` |
## Compilando a aplicação Go
@@ -115,7 +115,7 @@ CGO_CFLAGS=$(php-config --includes) \
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
xcaddy build \
--output frankenphp \
- --with github.com/dunglas/frankenphp/caddy \
+ --with github.com/php/frankenphp/caddy \
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain/caddy
# Adicione módulos Caddy e extensões FrankenPHP extras aqui
@@ -141,7 +141,7 @@ Alternativamente, é possível compilar o FrankenPHP sem o `xcaddy` usando o
comando `go` diretamente:
```console
-curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
+curl -L https://github.com/php/frankenphp/archive/refs/heads/main.tar.gz | tar xz
cd frankenphp-main/caddy/frankenphp
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build -tags=nobadger,nomysql,nopgx
```
diff --git a/docs/pt-br/config.md b/docs/pt-br/config.md
index c6641b7a..e36a144d 100644
--- a/docs/pt-br/config.md
+++ b/docs/pt-br/config.md
@@ -4,7 +4,7 @@ FrankenPHP, Caddy, bem como os módulos Mercure e Vulcain, podem ser configurado
usando
[os formatos suportados pelo Caddy](https://caddyserver.com/docs/getting-started#your-first-config).
-Nas [imagens do Docker](docker.md), o `Caddyfile` está localizado em
+Nas [imagens Docker](docker.md), o `Caddyfile` está localizado em
`/etc/frankenphp/Caddyfile`.
O binário estático também procurará pelo `Caddyfile` no diretório onde o comando
`frankenphp run` é executado.
@@ -19,9 +19,9 @@ arquivos de configuração nos locais descritos acima.
## Docker
- `php.ini`: `/usr/local/etc/php/php.ini` (nenhum `php.ini` é fornecido por
- padrão)
-- Arquivos de configuração adicionais: `/usr/local/etc/php/conf.d/*.ini`
-- Extensões PHP: `/usr/local/lib/php/extensions/no-debug-zts-/`
+ padrão);
+- Arquivos de configuração adicionais: `/usr/local/etc/php/conf.d/*.ini`;
+- Extensões PHP: `/usr/local/lib/php/extensions/no-debug-zts-/`;
- Você deve copiar um template oficial fornecido pelo projeto PHP:
```dockerfile
@@ -37,18 +37,18 @@ RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
## Pacotes RPM e Debian
- `php.ini`: `/etc/frankenphp/php.ini` (um arquivo `php.ini` com configurações
- de produção é fornecido por padrão)
-- Arquivos de configuração adicionais: `/etc/frankenphp/php.d/*.ini`
-- Extensões PHP: `/usr/lib/frankenphp/modules/`
+ de produção é fornecido por padrão);
+- Arquivos de configuração adicionais: `/etc/frankenphp/php.d/*.ini`;
+- Extensões PHP: `/usr/lib/frankenphp/modules/`.
## Binário estático
- `php.ini`: O diretório no qual `frankenphp run` ou `frankenphp php-server` é
- executado e, em seguida, `/etc/frankenphp/php.ini`
-- Arquivos de configuração adicionais: `/etc/frankenphp/php.d/*.ini`
-- Extensões PHP: não podem ser carregadas, empacote-as no próprio binário
-- Copie um dos `php.ini-production` ou `php.ini-development` fornecidos
- [nos fontes do PHP](https://github.com/php/php-src/).
+ executado e, em seguida, `/etc/frankenphp/php.ini`;
+- Arquivos de configuração adicionais: `/etc/frankenphp/php.d/*.ini`;
+- Extensões PHP: não podem ser carregadas, empacote-as no próprio binário;
+- Copie um dos arquivos `php.ini-production` ou `php.ini-development` fornecidos
+ [no código-fonte do PHP](https://github.com/php/php-src/).
## Configuração do Caddyfile
@@ -79,11 +79,12 @@ A [opção global](https://caddyserver.com/docs/caddyfile/concepts#global-option
max_wait_time # Define o tempo máximo que uma requisição pode esperar por uma thread PHP livre antes de atingir o tempo limite. Padrão: disabled.
php_ini # Define uma diretiva php.ini. Pode ser usada várias vezes para definir múltiplas diretivas.
worker {
- file # Define o caminho para o script do worker.
+ file # Define o caminho para o worker script.
num # Define o número de threads PHP a serem iniciadas, o padrão é 2x o número de CPUs disponíveis.
- env # Define uma variável de ambiente extra para o valor fornecido. Pode ser especificado mais de uma vez para múltiplas variáveis de ambiente.
- watch # Define o caminho para monitorar alterações no arquivo. Pode ser especificado mais de uma vez para múltiplos caminhos.
+ env # Define uma variável de ambiente extra para o valor fornecido. Pode ser especificada mais de uma vez para múltiplas variáveis de ambiente.
+ watch # Define o caminho para monitorar alterações em arquivos. Pode ser especificada mais de uma vez para múltiplos caminhos.
name # Define o nome do worker, usado em logs e métricas. Padrão: caminho absoluto do arquivo do worker.
+ max_consecutive_failures # Define o número máximo de falhas consecutivas antes do worker ser considerado inoperante. -1 significa que o worker sempre reiniciará. Padrão: 6.
}
}
}
@@ -109,13 +110,15 @@ servidor:
```caddyfile
app.example.com {
+ root /caminho/para/aplicacao/public
php_server {
- root /caminho/para/aplicacao/public
+ root /caminho/para/aplicacao/public # permite melhor armazenamento em cache
worker index.php
}
}
outra.example.com {
+ root /caminho/para/outra/aplicacao/public
php_server {
root /caminho/para/outra/aplicacao/public
worker index.php
@@ -162,14 +165,15 @@ php_server [] {
root # Define a pasta raiz para o site. Padrão: diretiva `root`.
split_path # Define as substrings para dividir o URI em duas partes. A primeira substring correspondente será usada para separar as "informações de caminho" do caminho. A primeira parte é sufixada com a substring correspondente e será assumida como o nome real do recurso (script CGI). A segunda parte será definida como PATH_INFO para o script usar. Padrão: `.php`
resolve_root_symlink false # Desabilita a resolução do diretório `root` para seu valor real avaliando um link simbólico, se houver (habilitado por padrão).
- env # Define uma variável de ambiente extra para o valor fornecido. Pode ser especificado mais de uma vez para múltiplas variáveis de ambiente.
+ env # Define uma variável de ambiente extra para o valor fornecido. Pode ser especificada mais de uma vez para múltiplas variáveis de ambiente.
file_server off # Desabilita a diretiva interna file_server.
- worker { # Cria um worker específico para este servidor. Pode ser especificado mais de uma vez para múltiplos workers.
- file # Define o caminho para o script do worker, pode ser relativo à raiz do php_server
- num # Define o número de threads PHP a serem iniciadas, o padrão é 2x o número de threads disponíveis
+ worker { # Cria um worker específico para este servidor. Pode ser especificada mais de uma vez para múltiplos workers.
+ file # Define o caminho para o worker script, pode ser relativo à raiz do php_server.
+ num # Define o número de threads PHP a serem iniciadas, o padrão é 2x o número de threads disponíveis.
name # Define o nome do worker, usado em logs e métricas. Padrão: caminho absoluto do arquivo do worker. Sempre começa com m# quando definido em um bloco php_server.
- watch # Define o caminho para monitorar alterações no arquivo. Pode ser especificado mais de uma vez para múltiplos caminhos.
- env # Define uma variável de ambiente extra para o valor fornecido. Pode ser especificado mais de uma vez para múltiplas variáveis de ambiente. As variáveis de ambiente para este worker também são herdadas do php_server pai, mas podem ser sobrescritas aqui.
+ watch # Define o caminho para monitorar alterações em arquivos. Pode ser especificada mais de uma vez para múltiplos caminhos.
+ env # Define uma variável de ambiente extra para o valor fornecido. Pode ser especificada mais de uma vez para múltiplas variáveis de ambiente. As variáveis de ambiente para este worker também são herdadas do pai do php_server, mas podem ser sobrescritas aqui.
+ match # Corresponde o worker a um padrão de caminho. Substitui try_files e só pode ser usada na diretiva php_server.
}
worker # Também pode usar a forma abreviada, como no bloco global frankenphp.
}
@@ -180,7 +184,7 @@ php_server [] {
Como os workers inicializam sua aplicação apenas uma vez e a mantêm na memória,
quaisquer alterações nos seus arquivos PHP não serão refletidas imediatamente.
-Os workers podem ser reiniciados em caso de alterações nos arquivos por meio da
+Os workers podem ser reiniciados em caso de alterações em arquivos por meio da
diretiva `watch`.
Isso é útil para ambientes de desenvolvimento.
@@ -224,9 +228,37 @@ Você também pode especificar um ou mais diretórios por meio de um
- Tenha cuidado ao monitorar arquivos criados em tempo de execução (como logs),
pois eles podem causar reinicializações indesejadas de workers.
-O monitor de arquivos é baseado em
+O monitor de arquivos é baseado no
[e-dant/watcher](https://github.com/e-dant/watcher).
+## Correspondendo o worker a um caminho
+
+Em aplicações PHP tradicionais, os scripts são sempre colocados no diretório
+público.
+Isso também se aplica aos worker scripts, que são tratados como qualquer outro
+script PHP.
+Se você quiser colocar o worker script fora do diretório público, pode fazê-lo
+por meio da diretiva `match`.
+
+A diretiva `match` é uma alternativa otimizada ao `try_files`, disponível apenas
+dentro do `php_server` e do `php`.
+O exemplo a seguir sempre servirá um arquivo no diretório público, se presente,
+e, caso contrário, encaminhará a requisição para o worker que corresponde ao
+padrão de caminho.
+
+```caddyfile
+{
+ frankenphp {
+ php_server {
+ worker {
+ file /caminho/para/worker.php # arquivo pode estar fora do caminho público
+ match /api/* # todas as requisições que começam com /api/ serão tratadas por este worker
+ }
+ }
+ }
+}
+```
+
### Full Duplex (HTTP/1)
Ao usar HTTP/1.x, pode ser desejável habilitar o modo full-duplex para permitir
@@ -267,10 +299,10 @@ no `Caddyfile` sem modificá-lo:
- `SERVER_NAME`: altera
[os endereços nos quais escutar](https://caddyserver.com/docs/caddyfile/concepts#addresses),
- os nomes de host fornecidos também serão usados para o certificado TLS gerado.
-- `SERVER_ROOT`: altera o diretório raiz do site, o padrão é `public/`.
+ os nomes de host fornecidos também serão usados para o certificado TLS gerado;
+- `SERVER_ROOT`: altera o diretório raiz do site, o padrão é `public/`;
- `CADDY_GLOBAL_OPTIONS`: injeta
- [opções globais](https://caddyserver.com/docs/caddyfile/options).
+ [opções globais](https://caddyserver.com/docs/caddyfile/options);
- `FRANKENPHP_CONFIG`: injeta a configuração sob a diretiva `frankenphp`.
Quanto às SAPIs FPM e CLI, as variáveis de ambiente são expostas por padrão na
@@ -309,7 +341,7 @@ Você também pode alterar a configuração do PHP usando a diretiva `php_ini` n
## Habilitar o modo de depuração
-Ao usar a imagem do Docker, defina a variável de ambiente `CADDY_GLOBAL_OPTIONS`
+Ao usar a imagem Docker, defina a variável de ambiente `CADDY_GLOBAL_OPTIONS`
como `debug` para habilitar o modo de depuração:
```console
diff --git a/docs/pt-br/docker.md b/docs/pt-br/docker.md
index 5c9d131b..aaf9f3ec 100644
--- a/docs/pt-br/docker.md
+++ b/docs/pt-br/docker.md
@@ -29,7 +29,7 @@ FROM dunglas/frankenphp
COPY . /app/public
```
-Em seguida, execute estes comandos para compilar e executar a imagem do Docker:
+Em seguida, execute estes comandos para construir e executar a imagem Docker:
```console
docker build -t minha-app-php .
@@ -55,13 +55,13 @@ RUN install-php-extensions \
opcache
```
-## Como instalar mais módulos do Caddy
+## Como instalar mais módulos Caddy
O FrankenPHP é construído sobre o Caddy, e todos os
-[módulos do Caddy](https://caddyserver.com/docs/modules/) podem ser usados com o
+[módulos Caddy](https://caddyserver.com/docs/modules/) podem ser usados com o
FrankenPHP.
-A maneira mais fácil de instalar módulos personalizados do Caddy é usar o
+A maneira mais fácil de instalar módulos Caddy personalizados é usar o
[xcaddy](https://github.com/caddyserver/xcaddy):
```dockerfile
@@ -78,8 +78,8 @@ RUN CGO_ENABLED=1 \
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
xcaddy build \
--output /usr/local/bin/frankenphp \
- --with github.com/dunglas/frankenphp=./ \
- --with github.com/dunglas/frankenphp/caddy=./caddy/ \
+ --with github.com/php/frankenphp=./ \
+ --with github.com/php/frankenphp/caddy=./caddy/ \
--with github.com/dunglas/caddy-cbrotli \
# Mercure e Vulcain estão incluídos na compilação oficial, mas sinta-se
# à vontade para removê-los
@@ -93,10 +93,10 @@ FROM dunglas/frankenphp AS runner
COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
```
-A imagem `builder` fornecida pelo FrankenPHP contém uma versão compilada de
+A imagem `builder` fornecida pelo FrankenPHP contém uma versão compilada da
`libphp`.
[Imagens de builder](https://hub.docker.com/r/dunglas/frankenphp/tags?name=builder)
-são fornecidas para todas as versões do FrankenPHP e PHP, tanto para Debian
+são fornecidas para todas as versões do FrankenPHP e do PHP, tanto para Debian
quanto para Alpine.
> [!TIP]
@@ -177,8 +177,8 @@ RUN \
useradd ${USER}; \
# Adiciona capacidade adicional para vincular às portas 80 e 443
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \
- # Concede acesso de escrita a /data/caddy e /config/caddy
- chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy
+ # Concede acesso de escrita a /config/caddy e /data/caddy
+ chown -R ${USER}:${USER} /config/caddy /data/caddy
USER ${USER}
```
@@ -203,8 +203,8 @@ RUN \
useradd ${USER}; \
# Remove a capacidade padrão
setcap -r /usr/local/bin/frankenphp; \
- # Concede acesso de escrita a /data/caddy e /config/caddy
- chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy
+ # Concede acesso de escrita a /config/caddy e /data/caddy
+ chown -R ${USER}:${USER} /config/caddy /data/caddy
USER ${USER}
```
@@ -215,17 +215,17 @@ Exemplo: `:8000`
## Atualizações
-As imagens do Docker são compiladas:
+As imagens Docker são construídas:
-- quando uma tag de uma nova versão é criada.
-- diariamente às 4h UTC, se novas versões das imagens oficiais do PHP estiverem
+- Quando uma tag de uma nova versão é criada;
+- Diariamente às 4h UTC, se novas versões das imagens oficiais do PHP estiverem
disponíveis.
## Versões de desenvolvimento
As versões de desenvolvimento estão disponíveis no repositório Docker
[`dunglas/frankenphp-dev`](https://hub.docker.com/repository/docker/dunglas/frankenphp-dev).
-Uma nova compilação é acionada sempre que um commit é enviado para o branch
+Uma nova construção é acionada sempre que um commit é enviado para o branch
principal do repositório do GitHub.
As tags `latest*` apontam para o HEAD do branch `main`.
diff --git a/docs/pt-br/embed.md b/docs/pt-br/embed.md
index 0c28ebd9..41c34a78 100644
--- a/docs/pt-br/embed.md
+++ b/docs/pt-br/embed.md
@@ -1,6 +1,6 @@
# Aplicações PHP como binários independentes
-O FrankenPHP tem a capacidade de incorporar o código-fonte e os recursos de
+O FrankenPHP tem a capacidade de incorporar o código-fonte e os assets de
aplicações PHP em um binário estático e independente.
Graças a esse recurso, aplicações PHP podem ser distribuídas como binários
@@ -11,7 +11,7 @@ Saiba mais sobre esse recurso
[na apresentação feita por Kévin na SymfonyCon 2023](https://dunglas.dev/2023/12/php-and-symfony-apps-as-standalone-binaries/).
Para incorporar aplicações Laravel,
-[leia esta entrada específica na documentação](laravel.md#laravel-apps-as-standalone-binaries).
+[leia esta entrada específica na documentação](laravel.md#aplicacoes-laravel-como-binarios-independentes).
## Preparando sua aplicação
@@ -20,9 +20,9 @@ pronta para ser incorporada.
Por exemplo, você provavelmente deseja:
-- Instalar as dependências de produção da aplicação.
-- Fazer o dump do carregador automático.
-- Habilitar o modo de produção da sua aplicação (se houver).
+- Instalar as dependências de produção da aplicação;
+- Fazer o dump do carregador automático;
+- Habilitar o modo de produção da sua aplicação (se houver);
- Remover arquivos desnecessários, como `.git` ou testes, para reduzir o tamanho
do seu binário final.
@@ -83,7 +83,7 @@ Docker que fornecemos.
> [`.dockerignore` padrão do Docker do Symfony](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore))
> ignorarão o diretório `vendor/` e os arquivos `.env`.
> Certifique-se de ajustar ou remover o arquivo `.dockerignore` antes da
- > compilação.
+ > construção.
2. Construa:
@@ -105,7 +105,7 @@ Se você não quiser usar o Docker ou quiser compilar um binário para macOS, us
script de shell que fornecemos:
```console
-git clone https://github.com/dunglas/frankenphp
+git clone https://github.com/php/frankenphp
cd frankenphp
EMBED=/caminho/para/sua/aplicacao ./build-static.sh
```
@@ -145,8 +145,8 @@ Você também pode executar os scripts PHP CLI incorporados ao seu binário:
## Extensões PHP
-Por padrão, o script criará as extensões requeridas pelo arquivo `composer.json`
-do seu projeto, se houver.
+Por padrão, o script compilará as extensões requeridas pelo arquivo
+`composer.json` do seu projeto, se houver.
Se o arquivo `composer.json` não existir, as extensões padrão serão compiladas,
conforme documentado na [entrada de compilações estáticas](static.md).
diff --git a/docs/pt-br/extensions.md b/docs/pt-br/extensions.md
new file mode 100644
index 00000000..3d512c1b
--- /dev/null
+++ b/docs/pt-br/extensions.md
@@ -0,0 +1,1001 @@
+# Escrevendo extensões PHP em Go
+
+Com o FrankenPHP, você pode **escrever extensões PHP em Go**, o que permite
+criar **funções nativas de alto desempenho** que podem ser chamadas diretamente
+do PHP.
+Suas aplicações podem aproveitar qualquer biblioteca Go existente ou nova, bem
+como o famoso modelo de concorrência de **goroutines diretamente do seu código
+PHP**.
+
+Escrever extensões PHP normalmente é feito em C, mas também é possível
+escrevê-las em outras linguagens com um pouco de trabalho extra.
+As extensões PHP permitem que você aproveite o poder das linguagens de baixo
+nível para estender as funcionalidades do PHP, por exemplo, adicionando funções
+nativas ou otimizando operações específicas.
+
+Graças aos módulos Caddy, você pode escrever extensões PHP em Go e integrá-las
+rapidamente ao FrankenPHP.
+
+## Duas abordagens
+
+O FrankenPHP oferece duas maneiras de criar extensões PHP em Go:
+
+1. **Usando o gerador de extensões** - A abordagem recomendada que gera todo o
+ código boilerplate necessário para a maioria dos casos de uso, permitindo que
+ você se concentre em escrever seu código em Go.
+2. **Implementação manual** - Controle total sobre a estrutura da extensão para
+ casos de uso avançados.
+
+Começaremos com a abordagem do gerador, pois é a maneira mais fácil de começar,
+e, em seguida, mostraremos a implementação manual para aqueles que precisam de
+controle total.
+
+## Usando o gerador de extensões
+
+O FrankenPHP vem com uma ferramenta que permite **criar uma extensão PHP**
+usando apenas Go.
+**Não é necessário escrever código C** ou usar CGO diretamente: o FrankenPHP
+também inclui uma **API de tipos pública** para ajudar você a escrever suas
+extensões em Go sem ter que se preocupar com **o malabarismo de tipos entre
+PHP/C e Go**.
+
+> [!TIP]
+> Se quiser entender como as extensões podem ser escritas em Go do zero, leia a
+> seção de implementação manual abaixo, que demonstra como escrever uma extensão
+> PHP em Go sem usar o gerador.
+
+Lembre-se de que esta ferramenta **não é um gerador de extensões completo**.
+Ela foi criada para ajudar você a escrever extensões simples em Go, mas não
+oferece os recursos mais avançados das extensões PHP.
+Se precisar escrever uma extensão mais **complexa e otimizada**, talvez seja
+necessário escrever algum código em C ou usar CGO diretamente.
+
+### Pré-requisitos
+
+Conforme abordado na seção de implementação manual abaixo, você precisa
+[obter o código-fonte do PHP](https://www.php.net/downloads.php) e criar um novo
+módulo Go.
+
+#### Criando um novo módulo e obtendo o código-fonte do PHP
+
+O primeiro passo para escrever uma extensão PHP em Go é criar um novo módulo Go.
+Você pode usar o seguinte comando para isso:
+
+```console
+go mod init github.com//
+```
+
+O segundo passo é
+[obter o código-fonte do PHP](https://www.php.net/downloads.php) para os
+próximos passos.
+Depois de obtê-los, descompacte-os no diretório de sua escolha, não dentro do
+seu módulo Go:
+
+```console
+tar xf php-*
+```
+
+### Escrevendo a extensão
+
+Agora tudo está configurado para escrever sua função nativa em Go.
+Crie um novo arquivo chamado `stringext.go`.
+Nossa primeira função receberá uma string como argumento, o número de vezes que
+ela será repetida, um booleano para indicar se a string deve ser invertida e
+retornará a string resultante.
+Deve ficar assim:
+
+```go
+import (
+ "C"
+ "github.com/dunglas/frankenphp"
+ "strings"
+)
+
+//export_php:function repeat_this(string $str, int $count, bool $reverse): string
+func repeat_this(s *C.zend_string, count int64, reverse bool) unsafe.Pointer {
+ str := frankenphp.GoString(unsafe.Pointer(s))
+
+ result := strings.Repeat(str, int(count))
+ if reverse {
+ runes := []rune(result)
+ for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
+ runes[i], runes[j] = runes[j], runes[i]
+ }
+ result = string(runes)
+ }
+
+ return frankenphp.PHPString(result, false)
+}
+```
+
+Há duas coisas importantes a serem observadas aqui:
+
+- Um comentário de diretiva `//export_php:function` define a assinatura da
+ função no PHP.
+ É assim que o gerador sabe como gerar a função PHP com os parâmetros e o tipo
+ de retorno corretos;
+- A função deve retornar um `unsafe.Pointer`.
+ O FrankenPHP fornece uma API para ajudar você com o malabarismo de tipos entre
+ C e Go.
+
+Embora o primeiro ponto fale por si, o segundo pode ser mais difícil de
+entender.
+Vamos nos aprofundar no malabarismo de tipos na próxima seção.
+
+### Malabarismo de tipos
+
+Embora alguns tipos de variáveis tenham a mesma representação de memória entre
+C/PHP e Go, alguns tipos exigem mais lógica para serem usados diretamente.
+Esta talvez seja a parte mais difícil quando se trata de escrever extensões,
+pois requer a compreensão dos componentes internos da Zend Engine e de como as
+variáveis são armazenadas internamente no PHP.
+Esta tabela resume o que você precisa saber:
+
+| Tipo PHP | Tipo Go | Conversão direta | Auxiliar de C para Go | Auxiliar de Go para C | Suporte a métodos de classe |
+|--------------------|-------------------------------|------------------|-----------------------------------|------------------------------------|-----------------------------|
+| `int` | `int64` | ✅ | - | - | ✅ |
+| `?int` | `*int64` | ✅ | - | - | ✅ |
+| `float` | `float64` | ✅ | - | - | ✅ |
+| `?float` | `*float64` | ✅ | - | - | ✅ |
+| `bool` | `bool` | ✅ | - | - | ✅ |
+| `?bool` | `*bool` | ✅ | - | - | ✅ |
+| `?bool` | `*bool` | ✅ | - | - | ✅ |
+| `string`/`?string` | `*C.zend_string` | ❌ | `frankenphp.GoString()` | `frankenphp.PHPString()` | ✅ |
+| `array` | `frankenphp.AssociativeArray` | ❌ | `frankenphp.GoAssociativeArray()` | `frankenphp.PHPAssociativeArray()` | ✅ |
+| `array` | `map[string]any` | ❌ | `frankenphp.GoMap()` | `frankenphp.PHPMap()` | ✅ |
+| `array` | `[]any` | ❌ | `frankenphp.GoPackedArray()` | `frankenphp.PHPPackedArray()` | ✅ |
+| `object` | `struct` | ❌ | _Ainda não implementado_ | _Ainda não implementado_ | ❌ |
+
+> [!NOTE]
+> Esta tabela ainda não é exaustiva e será completada à medida que a API de
+> tipos do FrankenPHP se tornar mais completa.
+>
+> Tipos primitivos e arrays são suportados atualmente, especificamente para
+> métodos de classe.
+> Objetos ainda não podem ser usados como parâmetros de métodos ou tipos de
+> retorno.
+
+Se você consultar o trecho de código da seção anterior, poderá ver que os
+auxiliares são usados para converter o primeiro parâmetro e o valor de retorno.
+O segundo e o terceiro parâmetros da nossa função `repeat_this()` não precisam
+ser convertidos, pois a representação em memória dos tipos subjacentes é a mesma
+para C e Go.
+
+#### Trabalhando com arrays
+
+O FrankenPHP oferece suporte nativo para arrays PHP por meio de
+`frankenphp.AssociativeArray` ou conversão direta para um mapa ou slice.
+
+`AssociativeArray` representa um
+[hashmap](https://en.wikipedia.org/wiki/Hash_table) composto por um campo
+`Map: map[string]any` e um campo opcional `Order: []string` (ao contrário dos
+arrays associativos do PHP, os mapas em Go não são ordenados).
+
+Se a ordem ou a associação não forem necessárias, também é possível converter
+diretamente para um slice `[]any` ou um mapa não ordenado `map[string]any`.
+
+**Criando e manipulando arrays em Go:**
+
+```go
+//export_php:function process_data_ordered(array $input): array
+func process_data_ordered_map(arr *C.zval) unsafe.Pointer {
+ // Converte um array associativo PHP para Go, mantendo a ordem
+ associativeArray := frankenphp.GoAssociativeArray(unsafe.Pointer(arr))
+
+ // percorre as entradas em ordem
+ for _, key := range associativeArray.Order {
+ value, _ = associativeArray.Map[key]
+ // faz algo com a chave e o valor
+ }
+
+ // retorna um array ordenado
+ // se 'Order' não estiver vazio, apenas os pares chave-valor em 'Order'
+ // serão respeitados
+ return frankenphp.PHPAssociativeArray(AssociativeArray{
+ Map: map[string]any{
+ "chave1": "valor1",
+ "chave2": "valor2",
+ },
+ Order: []string{"chave1", "chave2"},
+ })
+}
+
+//export_php:function process_data_unordered(array $input): array
+func process_data_unordered_map(arr *C.zval) unsafe.Pointer {
+ // Converte um array associativo PHP em um mapa Go sem manter a ordem
+ // Ignorar a ordem terá melhor desempenho
+ goMap := frankenphp.GoMap(unsafe.Pointer(arr))
+
+ // percorre as entradas sem nenhuma ordem específica
+ for key, value := range goMap {
+ // faz algo com a chave e o valor
+ }
+
+ // retorna um array não ordenado
+ return frankenphp.PHPMap(map[string]any{
+ "chave1": "valor1",
+ "chave2": "valor2",
+ })
+}
+
+//export_php:function process_data_packed(array $input): array
+func process_data_packed(arr *C.zval) unsafe.Pointer {
+ // Converte um array compactado PHP para Go
+ goSlice := frankenphp.GoPackedArray(unsafe.Pointer(arr), false)
+
+ // percorre o slice em ordem
+ for index, value := range goSlice {
+ // faz algo com a chave e o valor
+ }
+
+ // retorna um array compactado
+ return frankenphp.PHPackedArray([]any{"valor1", "valor2", "value3"})
+}
+```
+
+**Principais recursos da conversão de arrays:**
+
+- **Pares chave-valor ordenados** - Opção para manter a ordem do array
+ associativo;
+- **Otimizado para múltiplos casos** - Opção para ignorar a ordem para melhor
+ desempenho ou converter diretamente para um slice;
+- **Detecção automática de listas** - Ao converter para PHP, detecta
+ automaticamente se o array deve ser uma lista compactada ou um hashmap;
+- **Arrays aninhados** - Os arrays podem ser aninhados e converterão todos os
+ tipos suportados automaticamente (`int64`, `float64`, `string`, `bool`, `nil`,
+ `AssociativeArray`, `map[string]any`, `[]any`);
+- **Objetos não são suportados** - Atualmente, apenas tipos escalares e arrays
+ podem ser usados como valores.
+ Fornecer um objeto resultará em um valor `null` no array PHP.
+
+##### Métodos disponíveis: empacotado e associativo
+
+- `frankenphp.PHPAssociativeArray(arr frankenphp.AssociativeArray) unsafe.Pointer`
+ \- Converte para um array PHP ordenado com pares chave-valor;
+- `frankenphp.PHPMap(arr map[string]any) unsafe.Pointer` - Converte um mapa em
+ um array PHP não ordenado com pares chave-valor;
+- `frankenphp.PHPPackedArray(slice []any) unsafe.Pointer` - Converte um slice
+ em um array PHP compactado apenas com valores indexados;
+- `frankenphp.GoAssociativeArray(arr unsafe.Pointer, ordered bool) frankenphp.AssociativeArray`
+ \- Converte um array PHP em um `AssociativeArray` Go ordenado (mapa com ordem);
+- `frankenphp.GoMap(arr unsafe.Pointer) map[string]any` - Converte um array PHP
+ em um mapa Go não ordenado;
+- `frankenphp.GoPackedArray(arr unsafe.Pointer) []any` - Converte um array PHP
+ em um slice Go.
+
+### Declarando uma classe PHP nativa
+
+O gerador suporta a declaração de **classes opacas** como estruturas Go, que
+podem ser usadas para criar objetos PHP.
+Você pode usar o comentário de diretiva `//export_php:class` para definir uma
+classe PHP.
+Por exemplo:
+
+```go
+//export_php:class User
+type UserStruct struct {
+ Name string
+ Age int
+}
+```
+
+#### O que são classes opacas?
+
+**Classes Opacas** são classes cuja estrutura interna (propriedades) é ocultada
+do código PHP.
+Isso significa:
+
+- **Sem acesso direto às propriedades**: Você não pode ler ou escrever
+ propriedades diretamente do PHP (`$user->name` não funcionará);
+- **Interface somente para métodos** - Todas as interações devem passar pelos
+ métodos que você definir;
+- **Melhor encapsulamento** - A estrutura interna de dados é completamente
+ controlada pelo código Go;
+- **Segurança de tipos** - Sem risco do código PHP corromper o estado interno
+ com tipos incorretos;
+- **API mais limpa** - Força o design de uma interface pública adequada.
+
+Essa abordagem fornece melhor encapsulamento e evita que o código PHP corrompa
+acidentalmente o estado interno dos seus objetos Go.
+Todas as interações com o objeto devem passar pelos métodos que você definir
+explicitamente.
+
+#### Adicionando métodos às classes
+
+Como as propriedades não são diretamente acessíveis, você **deve definir
+métodos** para interagir com suas classes opacas.
+Use a diretiva `//export_php:method` para definir o comportamento:
+
+```go
+//export_php:class User
+type UserStruct struct {
+ Name string
+ Age int
+}
+
+//export_php:method User::getName(): string
+func (us *UserStruct) GetUserName() unsafe.Pointer {
+ return frankenphp.PHPString(us.Name, false)
+}
+
+//export_php:method User::setAge(int $age): void
+func (us *UserStruct) SetUserAge(age int64) {
+ us.Age = int(age)
+}
+
+//export_php:method User::getAge(): int
+func (us *UserStruct) GetUserAge() int64 {
+ return int64(us.Age)
+}
+
+//export_php:method User::setNamePrefix(string $prefix = "User"): void
+func (us *UserStruct) SetNamePrefix(prefix *C.zend_string) {
+ us.Name = frankenphp.GoString(unsafe.Pointer(prefix)) + ": " + us.Name
+}
+```
+
+#### Parâmetros anuláveis
+
+O gerador suporta parâmetros anuláveis usando o prefixo `?` em assinaturas PHP.
+Quando um parâmetro é anulável, ele se torna um ponteiro na sua função Go,
+permitindo que você verifique se o valor era `null` no PHP:
+
+```go
+//export_php:method User::updateInfo(?string $name, ?int $age, ?bool $active): void
+func (us *UserStruct) UpdateInfo(name *C.zend_string, age *int64, active *bool) {
+ // Verifica se o parâmetro name foi fornecido (não nulo)
+ if name != nil {
+ us.Name = frankenphp.GoString(unsafe.Pointer(name))
+ }
+
+ // Verifica se o parâmetro age foi fornecido (não nulo)
+ if age != nil {
+ us.Age = int(*age)
+ }
+
+ // Verifique se o parâmetro active foi fornecido (não nulo)
+ if active != nil {
+ us.Active = *active
+ }
+}
+```
+
+**Pontos-chave sobre parâmetros anuláveis:**
+
+- **Tipos primitivos anuláveis** (`?int`, `?float`, `?bool`) tornam-se ponteiros
+ (`*int64`, `*float64`, `*bool`) em Go;
+- **Strings anuláveis** (`?string`) permanecem como `*C.zend_string`, mas podem
+ ser `*nil`;
+- **Verifique `nil`** antes de dereferenciar valores de ponteiro;
+- **`null` do PHP torna-se `nil` do Go** - quando o PHP passa `null`, sua função
+ em Go recebe um ponteiro `nil`.
+
+> [!WARNING]
+> Atualmente, os métodos de classe têm as seguintes limitações.
+> **Objetos não são suportados** como tipos de parâmetros ou tipos de retorno.
+> **Arrays são totalmente suportados** tanto para parâmetros quanto para tipos
+> de retorno.
+> Tipos suportados: `string`, `int`, `float`, `bool`, `array` e `void` (para
+> tipo de retorno).
+> **Tipos de parâmetros anuláveis são totalmente suportados** para todos os
+> tipos escalares (`?string`, `?int`, `?float`, `?bool`).
+
+Após gerar a extensão, você poderá usar a classe e seus métodos no PHP.
+Observe que você **não pode acessar propriedades diretamente**:
+
+```php
+setAge(25);
+echo $user->getName(); // Saída: (vazio, valor padrão)
+echo $user->getAge(); // Saída: 25
+$user->setNamePrefix("Funcionária");
+
+// ✅ Isso também funciona - parâmetros anuláveis
+$user->updateInfo("João", 30, true); // Todos os parâmetros fornecidos
+$user->updateInfo("Joana", null, false); // Age é nulo
+$user->updateInfo(null, 25, null); // Name e active são nulos
+
+// ❌ Isso NÃO funcionará - acesso direto à propriedade
+// echo $user->name; // Error: Cannot access private property
+// $user->age = 30; // Error: Cannot access private property
+```
+
+Este design garante que seu código Go tenha controle total sobre como o estado
+do objeto é acessado e modificado, proporcionando melhor encapsulamento e
+segurança de tipos.
+
+### Declarando constantes
+
+O gerador suporta a exportação de constantes Go para PHP usando duas diretivas:
+`//export_php:const` para constantes globais e `//export_php:classconstant` para
+constantes de classe.
+Isso permite que você compartilhe valores de configuração, códigos de status e
+outras constantes entre código Go e PHP.
+
+#### Constantes globais
+
+Use a diretiva `//export_php:const` para criar constantes PHP globais:
+
+```go
+//export_php:const
+const MAX_CONNECTIONS = 100
+
+//export_php:const
+const API_VERSION = "1.2.3"
+
+//export_php:const
+const STATUS_OK = iota
+
+//export_php:const
+const STATUS_ERROR = iota
+```
+
+#### Constantes de classe
+
+Use a diretiva `//export_php:classconstant ClassName` para criar constantes que
+pertencem a uma classe PHP específica:
+
+```go
+//export_php:classconstant User
+const STATUS_ACTIVE = 1
+
+//export_php:classconstant User
+const STATUS_INACTIVE = 0
+
+//export_php:classconstant User
+const ROLE_ADMIN = "admin"
+
+//export_php:classconstant Order
+const STATE_PENDING = iota
+
+//export_php:classconstant Order
+const STATE_PROCESSING = iota
+
+//export_php:classconstant Order
+const STATE_COMPLETED = iota
+```
+
+Constantes de classe são acessíveis usando o escopo do nome da classe no PHP:
+
+```php
+getName(); // "João Ninguém"
+
+echo My\Extension\STATUS_ACTIVE; // 1
+```
+
+#### Notas importantes
+
+- Apenas **uma** diretiva de namespace é permitida por arquivo.
+ Se várias diretivas de namespace forem encontradas, o gerador retornará um
+ erro;
+- O namespace se aplica a **todos** os símbolos exportados no arquivo: funções,
+ classes, métodos e constantes;
+- Os nomes de namespace seguem as convenções de namespace do PHP, usando barras
+ invertidas (`\`) como separadores;
+- Se nenhum namespace for declarado, os símbolos serão exportados para o
+ namespace global como de costume.
+
+### Gerando a extensão
+
+É aqui que a mágica acontece e sua extensão agora pode ser gerada.
+Você pode executar o gerador com o seguinte comando:
+
+```console
+GEN_STUB_FILE=php-src/build/gen_stub.php frankenphp extension-init my_extension.go
+```
+
+> [!NOTE]
+> Não se esqueça de definir a variável de ambiente `GEN_STUB_FILE` para o
+> caminho do arquivo `gen_stub.php` no código-fonte PHP que você baixou
+> anteriormente.
+> Este é o mesmo script `gen_stub.php` mencionado na seção de implementação
+> manual.
+
+Se tudo correu bem, um novo diretório chamado `build` deve ter sido criado.
+Este diretório contém os arquivos gerados para sua extensão, incluindo o arquivo
+`my_extension.go` com os stubs de funções PHP gerados.
+
+### Integrando a extensão gerada ao FrankenPHP
+
+Nossa extensão agora está pronta para ser compilada e integrada ao FrankenPHP.
+Para fazer isso, consulte a [documentação de compilação](compile.md) do
+FrankenPHP para aprender como compilar o FrankenPHP.
+Adicione o módulo usando a flag `--with`, apontando para o caminho do seu
+módulo:
+
+```console
+CGO_ENABLED=1 \
+XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \
+CGO_CFLAGS=$(php-config --includes) \
+CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
+xcaddy build \
+ --output frankenphp \
+ --with github.com///build
+```
+
+Observe que você aponta para o subdiretório `/build` que foi criado durante a
+etapa de geração.
+Entretanto, isso não é obrigatório: você também pode copiar os arquivos gerados
+para o diretório do seu módulo e apontar diretamente para ele.
+
+### Testando sua extensão gerada
+
+Você pode criar um arquivo PHP para testar as funções e classes que criou.
+Por exemplo, crie um arquivo `index.php` com o seguinte conteúdo:
+
+```php
+process('Olá mundo', StringProcessor::MODE_LOWERCASE); // "olá mundo"
+echo $processor->process('Olá mundo', StringProcessor::MODE_UPPERCASE); // "OLÁ MUNDO"
+```
+
+Depois de integrar sua extensão ao FrankenPHP, como demonstrado na seção
+anterior, você pode executar este arquivo de teste usando
+`./frankenphp php-server` e deverá ver sua extensão funcionando.
+
+## Implementação manual
+
+Se você quiser entender como as extensões funcionam ou precisar de controle
+total sobre elas, pode escrevê-las manualmente.
+Essa abordagem oferece controle total, mas requer mais código boilerplate.
+
+### Função básica
+
+Veremos como escrever uma extensão PHP simples em Go que define uma nova função
+nativa.
+Essa função será chamada do PHP e disparará uma goroutine que registra uma
+mensagem nos logs do Caddy.
+Essa função não recebe parâmetros e não retorna nada.
+
+#### Definindo a função Go
+
+No seu módulo, você precisa definir uma nova função nativa que será chamada do
+PHP.
+Para fazer isso, crie um arquivo com o nome desejado, por exemplo,
+`extension.go`, e adicione o seguinte código:
+
+```go
+package ext_go
+
+//#include "extension.h"
+import "C"
+import (
+ "unsafe"
+ "github.com/caddyserver/caddy/v2"
+ "github.com/dunglas/frankenphp"
+)
+
+func init() {
+ frankenphp.RegisterExtension(unsafe.Pointer(&C.ext_module_entry))
+}
+
+//export go_print_something
+func go_print_something() {
+ go func() {
+ caddy.Log().Info("Olá de uma goroutine!")
+ }()
+}
+```
+
+A função `frankenphp.RegisterExtension()` simplifica o processo de registro de
+extensões, manipulando a lógica interna de registro do PHP.
+A função `go_print_something` usa a diretiva `//export` para indicar que estará
+acessível no código C que escreveremos, graças ao CGO.
+
+Neste exemplo, nossa nova função disparará uma goroutine que registra uma
+mensagem nos logs do Caddy.
+
+#### Definindo a função PHP
+
+Para permitir que o PHP chame nossa função, precisamos definir uma função PHP
+correspondente.
+Para isso, criaremos um arquivo stub, por exemplo, `extension.stub.php`, que
+conterá o seguinte código:
+
+```php
+
+
+extern zend_module_entry ext_module_entry;
+
+#endif
+```
+
+Em seguida, crie um arquivo chamado `extension.c` que executará as seguintes
+etapas:
+
+- Incluir cabeçalhos PHP;
+- Declarar nossa nova função nativa PHP `go_print()`;
+- Declarar os metadados da extensão.
+
+Vamos começar incluindo os cabeçalhos necessários:
+
+```c
+#include
+#include "extension.h"
+#include "extension_arginfo.h"
+
+// Contém símbolos exportados pelo Go
+#include "_cgo_export.h"
+```
+
+Em seguida, definimos nossa função PHP como uma função nativa da linguagem:
+
+```c
+PHP_FUNCTION(go_print)
+{
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ go_print_something();
+}
+
+zend_module_entry ext_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "ext_go",
+ ext_functions, /* Funções */
+ NULL, /* MINIT */
+ NULL, /* MSHUTDOWN */
+ NULL, /* RINIT */
+ NULL, /* RSHUTDOWN */
+ NULL, /* MINFO */
+ "0.1.1",
+ STANDARD_MODULE_PROPERTIES
+};
+```
+
+Neste caso, nossa função não recebe parâmetros e não retorna nada.
+Ela simplesmente chama a função Go que definimos anteriormente, exportada usando
+a diretiva `//export`.
+
+Finalmente, definimos os metadados da extensão em uma estrutura
+`zend_module_entry`, como seu nome, versão e propriedades.
+Essas informações são necessárias para que o PHP reconheça e carregue nossa
+extensão.
+Observe que `ext_functions` é um array de ponteiros para as funções PHP que
+definimos e foi gerado automaticamente pelo script `gen_stub.php` no arquivo
+`extension_arginfo.h`.
+
+O registro da extensão é tratado automaticamente pela função
+`RegisterExtension()` do FrankenPHP, que chamamos em nosso código Go.
+
+### Uso avançado
+
+Agora que sabemos como criar uma extensão PHP básica em Go, vamos tornar nosso
+exemplo mais complexo.
+Agora, criaremos uma função PHP que recebe uma string como parâmetro e retorna
+sua versão em letras maiúsculas.
+
+#### Definindo o stub da função PHP
+
+Para definir a nova função PHP, modificaremos nosso arquivo `extension.stub.php`
+para incluir a nova assinatura da função:
+
+```php
+ [!TIP]
+> Não negligencie a documentação das suas funções!
+> Você provavelmente compartilhará os stubs da sua extensão com outras
+> pessoas desenvolvedoras para documentar como usar a sua extensão e quais
+> recursos estão disponíveis.
+
+Ao gerar novamente o arquivo stub com o script `gen_stub.php`, o arquivo
+`extension_arginfo.h` deverá ficar assim:
+
+```c
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_go_upper, 0, 1, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_FUNCTION(go_upper);
+
+static const zend_function_entry ext_functions[] = {
+ ZEND_FE(go_upper, arginfo_go_upper)
+ ZEND_FE_END
+};
+```
+
+Podemos ver que a função `go_upper` é definida com um parâmetro do tipo `string`
+e um tipo de retorno `string`.
+
+#### Malabarismo de tipos entre Go e PHP/C
+
+Sua função Go não pode aceitar diretamente uma string PHP como parâmetro.
+Você precisa convertê-la para uma string Go.
+Felizmente, o FrankenPHP fornece funções auxiliares para lidar com a conversão
+entre strings PHP e strings Go, semelhante ao que vimos na abordagem do gerador.
+
+O arquivo de cabeçalho permanece simples:
+
+```c
+#ifndef _EXTENSION_H
+#define _EXTENSION_H
+
+#include
+
+extern zend_module_entry ext_module_entry;
+
+#endif
+```
+
+Agora podemos escrever a ponte entre Go e C no nosso arquivo `extension.c`.
+Passaremos a string PHP diretamente para a nossa função Go:
+
+```c
+PHP_FUNCTION(go_upper)
+{
+ zend_string *str;
+
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_STR(str)
+ ZEND_PARSE_PARAMETERS_END();
+
+ zend_string *result = go_upper(str);
+ RETVAL_STR(result);
+}
+```
+
+Você pode aprender mais sobre `ZEND_PARSE_PARAMETERS_START` e análise de
+parâmetros na página dedicada do
+[PHP Internals Book](https://www.phpinternalsbook.com/php7/extensions_design/php_functions.html#parsing-parameters-zend-parse-parameters).
+Aqui, informamos ao PHP que nossa função recebe um parâmetro obrigatório do tipo
+`string` como uma `zend_string`.
+Em seguida, passamos essa string diretamente para nossa função Go e retornamos o
+resultado usando `RETVAL_STR`.
+
+Só resta uma coisa a fazer: implementar a função `go_upper` em Go.
+
+#### Implementando a função Go
+
+Nossa função Go receberá uma `*C.zend_string` como parâmetro, a converterá em
+uma string Go usando a função auxiliar do FrankenPHP, a processará e retornará o
+resultado como uma nova `*C.zend_string`.
+As funções auxiliares cuidam de todo o gerenciamento de memória e da
+complexidade da conversão para nós.
+
+```go
+import "strings"
+
+//export go_upper
+func go_upper(s *C.zend_string) *C.zend_string {
+ str := frankenphp.GoString(unsafe.Pointer(s))
+
+ upper := strings.ToUpper(str)
+
+ return (*C.zend_string)(frankenphp.PHPString(upper, false))
+}
+```
+
+Essa abordagem é muito mais limpa e segura do que o gerenciamento manual de
+memória.
+As funções auxiliares do FrankenPHP lidam automaticamente com a conversão entre
+o formato `zend_string` do PHP e strings em Go.
+O parâmetro `false` em `PHPString()` indica que queremos criar uma nova string
+não persistente (liberada ao final da requisição).
+
+> [!TIP]
+> Neste exemplo, não realizamos nenhum tratamento de erro, mas você deve sempre
+> verificar se os ponteiros não são `nil` e se os dados são válidos antes de
+> usá-los em suas funções em Go.
+
+### Integrando a extensão ao FrankenPHP
+
+Nossa extensão agora está pronta para ser compilada e integrada ao FrankenPHP.
+Para isso, consulte a [documentação de compilação](compile.md) do FrankenPHP
+para aprender como compilar o FrankenPHP.
+Adicione o módulo usando a flag `--with`, apontando para o caminho do seu
+módulo:
+
+```console
+CGO_ENABLED=1 \
+XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \
+CGO_CFLAGS=$(php-config --includes) \
+CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
+xcaddy build \
+ --output frankenphp \
+ --with github.com//
+```
+
+Pronto!
+Sua extensão agora está integrada ao FrankenPHP e pode ser usada no seu código
+PHP.
+
+### Testando sua extensão
+
+Após integrar sua extensão ao FrankenPHP, você pode criar um arquivo `index.php`
+com exemplos para as funções que você implementou:
+
+```php
+ [!CAUTION]
>
-> O Docker pode ter uma camada de cache; certifique-se de ter a compilação
+> O Docker pode ter uma camada de cache; certifique-se de ter a construção
> correta para cada implantação ou reconstrua seu projeto com a opção
> `--no-cache` para evitar problemas de cache.
diff --git a/docs/pt-br/static.md b/docs/pt-br/static.md
index 05613397..3836099f 100644
--- a/docs/pt-br/static.md
+++ b/docs/pt-br/static.md
@@ -132,7 +132,7 @@ Execute o seguinte script para criar um binário estático para macOS (você
precisa ter o [Homebrew](https://brew.sh/) instalado):
```console
-git clone https://github.com/dunglas/frankenphp
+git clone https://github.com/php/frankenphp
cd frankenphp
./build-static.sh
```
@@ -145,34 +145,34 @@ sistemas Unix) e é usado internamente pelas imagens Docker que fornecemos.
As seguintes variáveis de ambiente podem ser passadas para `docker build` e para
o script `build-static.sh` para personalizar a compilação estática:
-- `FRANKENPHP_VERSION`: a versão do FrankenPHP a ser usada.
-- `PHP_VERSION`: a versão do PHP a ser usada.
+- `FRANKENPHP_VERSION`: a versão do FrankenPHP a ser usada;
+- `PHP_VERSION`: a versão do PHP a ser usada;
- `PHP_EXTENSIONS`: as extensões PHP a serem compiladas
- ([lista de extensões suportadas](https://static-php.dev/en/guide/extensions.html)).
+ ([lista de extensões suportadas](https://static-php.dev/en/guide/extensions.html));
- `PHP_EXTENSION_LIBS`: bibliotecas extras a serem compiladas que adicionam
- recursos às extensões.
+ recursos às extensões;
- `XCADDY_ARGS`: argumentos a passar para o
[`xcaddy`](https://github.com/caddyserver/xcaddy), por exemplo, para adicionar
- módulos Caddy extras.
-- `EMBED`: caminho da aplicação PHP a ser incorporada no binário.
+ módulos Caddy extras;
+- `EMBED`: caminho da aplicação PHP a ser incorporada no binário;
- `CLEAN`: quando definida, a `libphp` e todas as suas dependências são
- compiladas do zero (sem cache).
-- `NO_COMPRESS`: não compacta o binário resultante usando UPX.
+ compiladas do zero (sem cache);
+- `NO_COMPRESS`: não compacta o binário resultante usando UPX;
- `DEBUG_SYMBOLS`: quando definida, os símbolos de depuração não serão removidos
- e serão adicionados ao binário.
+ e serão adicionados ao binário;
- `MIMALLOC`: (experimental, somente Linux) substitui `mallocng` da `musl` por
[`mimalloc`](https://github.com/microsoft/mimalloc) para melhor desempenho.
Recomendamos usar isso apenas para compilações direcionadas à `musl`; para
`glibc`, prefira desabilitar essa opção e usar
[`LD_PRELOAD`](https://microsoft.github.io/mimalloc/overrides.html) ao
- executar seu binário.
+ executar seu binário;
- `RELEASE`: (somente pessoas mantenedoras) quando definida, o binário
resultante será enviado para o GitHub.
## Extensões
-Com os binários `glibc` ou baseados em macOS, você pode carregar extensões PHP
-dinamicamente.
+Com os binários baseados na `glibc` ou no macOS, você pode carregar extensões
+PHP dinamicamente.
No entanto, essas extensões precisarão ser compiladas com suporte a ZTS.
Como a maioria dos gerenciadores de pacotes não oferece atualmente versões ZTS
de suas extensões, você terá que compilá-las você mesmo.
diff --git a/docs/pt-br/worker.md b/docs/pt-br/worker.md
index a8867d06..a835be5f 100644
--- a/docs/pt-br/worker.md
+++ b/docs/pt-br/worker.md
@@ -8,11 +8,11 @@ O FrankenPHP processará as requisições recebidas em poucos milissegundos.
### Docker
Defina o valor da variável de ambiente `FRANKENPHP_CONFIG` como
-`worker /caminho/para/seu/script/worker.php`:
+`worker /caminho/para/seu/worker/script.php`:
```console
docker run \
- -e FRANKENPHP_CONFIG="worker /app/caminho/para/seu/script/worker.php" \
+ -e FRANKENPHP_CONFIG="worker /app/caminho/para/seu/worker/script.php" \
-v $PWD:/app \
-p 80:80 -p 443:443 -p 443:443/udp \
dunglas/frankenphp
@@ -24,7 +24,7 @@ Use a opção `--worker` do comando `php-server` para servir o conteúdo do
diretório atual usando um worker:
```console
-frankenphp php-server --worker /caminho/para/seu/script/worker.php
+frankenphp php-server --worker /caminho/para/seu/worker/script.php
```
Se a sua aplicação PHP estiver [embutida no binário](embed.md), você pode
@@ -32,30 +32,29 @@ adicionar um `Caddyfile` personalizado no diretório raiz da aplicação.
Ele será usado automaticamente.
Também é possível
-[reiniciar o worker em caso de alterações no arquivo](config.md#monitorando-alteracoes-em-arquivos)
+[reiniciar o worker em caso de alterações em arquivos](config.md#monitorando-alteracoes-em-arquivos)
com a opção `--watch`.
O comando a seguir acionará uma reinicialização se qualquer arquivo terminado em
`.php` no diretório `/caminho/para/sua/aplicacao/` ou subdiretórios for
modificado:
```console
-frankenphp php-server --worker /caminho/para/seu/script/worker.php --watch="/caminho/para/sua/aplicacao/**/*.php"
+frankenphp php-server --worker /caminho/para/seu/worker/script.php --watch="/caminho/para/sua/aplicacao/**/*.php"
```
-## Tempo de execução do Symfony
+## Symfony Runtime
O modo worker do FrankenPHP é suportado pelo
[Componente Symfony Runtime](https://symfony.com/doc/current/components/runtime.html).
Para iniciar qualquer aplicação Symfony em um worker, instale o pacote
-FrankenPHP do
-[tempo de execução do PHP](https://github.com/php-runtime/runtime):
+FrankenPHP do [PHP Runtime](https://github.com/php-runtime/runtime):
```console
composer require runtime/frankenphp-symfony
```
Inicie seu servidor de aplicações definindo a variável de ambiente `APP_RUNTIME`
-para usar o tempo de execução Symfony do FrankenPHP:
+para usar o Symfony Runtime do FrankenPHP:
```console
docker run \
@@ -83,7 +82,7 @@ uma biblioteca de terceiros:
// interrompida
ignore_user_abort(true);
-// Inicializa sua aplicação
+// Inicializa a aplicação
require __DIR__.'/vendor/autoload.php';
$myApp = new \App\Kernel();
@@ -125,7 +124,7 @@ docker run \
dunglas/frankenphp
```
-Por padrão, 2 workers por CPU são iniciados.
+Por padrão, são iniciados 2 workers por CPU.
Você também pode configurar o número de workers a serem iniciados:
```console
@@ -151,7 +150,7 @@ requisições a serem processadas, definindo uma variável de ambiente chamada
Embora seja possível reiniciar os workers
[em alterações de arquivo](config.md#monitorando-alteracoes-em-arquivos), também
-é possível reiniciar todos os workers normalmente por meio da
+é possível reiniciar todos os workers graciosamente por meio da
[API de administração do Caddy](https://caddyserver.com/docs/api).
Se o administrador estiver habilitado no seu
[Caddyfile](config.md#configuracao-do-caddyfile), você pode executar ping no
@@ -166,12 +165,24 @@ curl -X POST http://localhost:2019/frankenphp/workers/restart
Se um worker script travar com um código de saída diferente de zero, o
FrankenPHP o reiniciará com uma estratégia de backoff exponencial.
Se o worker script permanecer ativo por mais tempo do que o último backoff \* 2,
-ele não penalizará o worker script e o reiniciará novamente.
+ele não irá penalizar o worker script e reiniciá-lo novamente.
No entanto, se o worker script continuar a falhar com um código de saída
diferente de zero em um curto período de tempo (por exemplo, com um erro de
digitação em um script), o FrankenPHP travará com o erro:
`too many consecutive failures` (muitas falhas consecutivas).
+O número de falhas consecutivas pode ser configurado no seu
+[Caddyfile](config.md#caddyfile-config) com a opção `max_consecutive_failures`:
+
+```caddyfile
+frankenphp {
+ worker {
+ # ...
+ max_consecutive_failures 10
+ }
+}
+```
+
## Comportamento das superglobais
As
diff --git a/docs/pt-br/x-sendfile.md b/docs/pt-br/x-sendfile.md
index cb6405d3..6ad94043 100644
--- a/docs/pt-br/x-sendfile.md
+++ b/docs/pt-br/x-sendfile.md
@@ -9,10 +9,10 @@ comparação com o uso direto do servidor web (sobrecarga de memória, desempenh
reduzido...).
O FrankenPHP permite delegar o envio de arquivos estáticos ao servidor web
-**após** a execução de código PHP personalizado.
+**após** a execução do código PHP personalizado.
-Para fazer isso, sua aplicação PHP precisa simplesmente definir um cabeçalho
-HTTP personalizado contendo o caminho do arquivo a ser servido.
+Para fazer isso, sua aplicação PHP só precisa definir um cabeçalho HTTP
+personalizado contendo o caminho do arquivo a ser servido.
O FrankenPHP cuida do resto.
Esse recurso é conhecido como **`X-Sendfile`** para Apache e