
本文介绍如何使用开箱即用的 Docker 构建镜像,实现本地零 C++、零 PHP 环境依赖,仅需一行挂载命令,秒级完成原生二进制构建,同时完整记录构建过程输出等典型问题的解决方案。
Go 语言最受开发者推崇的优势之一,就是能将项目编译为单个无依赖的原生二进制文件,跨环境拷贝即运行,部署分发极其省心。而传统 PHP 项目的分发总要依赖运行环境、扩展配置与代码目录,部署繁琐、环境一致性问题频发。
TypePHP 是 Swoole 团队开源的 PHP 深度 AOT(Ahead-of-Time)原生静态编译器,可将 PHP 代码直接编译为原生汇编机器码,让 PHP 拥有媲美 Go / Rust 的启动速度与单文件分发能力。但本地配置 C++17、PHP 8.5 ZTS/Embed 开发库及 GCC/Clang 等复杂工具链,往往让很多开发者望而却步。
在工作目录下新建 main.php 作为编译入口:
declare(strict_types=1); function main(): int{ printf("Hello World from TypePHP Docker AOT!\n"); return 0;} |
|---|
⚠️ 注意:由于是直接编译为机器码,程序入口代码必须写在 function main(): int 函数内,标准输出使用 printf()。
在当前目录打开终端,根据你的系统选择对应 Docker 挂载命令执行:
docker run --rm -v "${PWD}:/app" tinywan/typephp-linux-x64:v0.7.0 |
|---|
docker run --rm -v "$(pwd):/app" tinywan/typephp-linux-x64:v0.7.0 |
|---|
docker run --rm -v "%cd%:/app" tinywan/typephp-linux-x64:v0.7.0 |
|---|
容器启动后会自动完成环境探测、代码转译与 C++ 深度编译,终端实时输出全流程日志:
[TypePHP] Working directory: /app[TypePHP] Detected PHP entrypoint: main.php[TypePHP] Auto-generating project.yml for app...[TypePHP] Generated project.yml:name: appbin: app.binsources: - main.php----------------------------------------[TypePHP] Starting AOT compilation via tpc...Initialized platform/backend: Linux + GCC (g++)prepare: main.phpprepare completed: 1 source files in totalconvert: main.phpgenerate arginfo file: main.php[pch] built: opt/typephp/vendor/swoole/typephp/build/cache/pch/31e80de1e5c0ecccc9195c7b/typephp_pch.hpp.gchStarting parallel compilation with 4 jobs for 6 filesCompiling [████████████████████████████████] 100% (6/6)Successfully compiled 6 filesg++ '@./app.rsp' -o 'app.bin' -L'/opt/typephp/vendor/swoole/phpx/lib' -L'/usr/lib' -lphpx -lphp -lgmp -lgmpxx -lmpfr -lstdc++Build successful: app.bin |
|---|
仅需数秒,当前目录下就会生成一个原生 Linux ELF 二进制文件 app.bin。
编译出的 app.bin 是 Linux 平台原生二进制文件,无需额外依赖,可直接通过同版本容器验证运行:
docker run --rm -v "${PWD}:/app" tinywan/typephp-linux-x64:v0.7.0 ./app.bin |
|---|
终端输出结果:
Hello World from TypePHP Docker AOT! |
|---|
Compiling [████████████████████████████████] 100% (6/6)Successfully compiled 6 filesg++ '@./app.rsp' -o 'app' -L'/opt/typephp/vendor/swoole/phpx/lib' -L'/usr/lib' -lphpx -lphp .../usr/bin/ld: cannot open output file app: Is a directorycollect2: error: ld returned 1 exit status |
|---|
多数现代 PHP 项目根目录下都会有一个存放业务代码的 app/ 目录。当 project.yml 中配置 name: app 时,链接器(ld)会默认将可执行文件输出为 ./app;由于同名目录已存在,系统无法用普通文件覆盖目录,因此抛出 Is a directory 错误。
在项目根目录的 project.yml 中,显式添加 bin: 字段指定输出文件名,避开同名目录即可:
name: appbin: app.bin # 显式指定二进制文件名(可自定义为 server、demo 等)sources: - app/index.php |
|---|
保存后重新执行编译命令,即可正常生成二进制文件。
如果目录下存在多个 PHP 脚本,可直接在命令末尾指定要编译的文件名:
docker run --rm -v "${PWD}:/app" tinywan/typephp-linux-x64:v0.7.0 your_script.php |
|---|
如果希望生成的二进制文件不依赖宿主机 glibc,可在任意 Linux 发行版甚至空白镜像(FROM scratch)中直接运行,更换全静态编译镜像即可:
docker run --rm -v "${PWD}:/app" tinywan/typephp-linux-x64-static:v0.7.0 |
|---|
镜像类型 | 镜像地址 | 适用场景 |
|---|---|---|
动态编译镜像(Ubuntu / glibc) | tinywan/typephp-linux-x64:v0.7.0 | 常规开发、本地测试 |
全静态单文件镜像(Alpine / musl) | tinywan/typephp-linux-x64-static:v0.7.0 | 生产分发、跨发行版运行、scratch 镜像部署 |