解决通过 php webman typephp:package 打包出的产物在执行 ./start.sh start 时出现的 Fatal error: Undefined constant "Monolog\Handler\Curl\CURLE_COULDNT_RESOLVE_HOST" 错误,并对标参考项目 tinywan-typephp-webman(GitHub Actions 成功构建的 Linux portable-dir),达到 100% 架构对齐与产物自包含运行。
通过深入对比 tinywan-typephp-webman-php8.5-linux-x64 与 webman-docker-build-demo/dist:
| 模块 | 参考标准产物 (tinywan-typephp-webman) |
当前插件打包产物 (webman-typephp) |
影响与故障现象 |
|---|---|---|---|
| Monolog 编译源 | 精准白名单 (Logger, LogRecord, StreamHandler 等核心类) |
粗暴全量 vendor/monolog/monolog/src |
包含了未提供对应扩展的 Handler(如 Curl/Util.php),启动即崩溃 |
PHP 扩展库 (ext/) |
包含 curl.so, pdo_mysql.so, posix.so 等完整扩展 |
完全缺失 ext/ 目录 |
运行时没有任何扩展可用 |
运行时配置 (php.ini) |
存在独立 php.ini,指定 extension_dir="./ext" 并按顺序加载各扩展 |
完全缺失 php.ini |
无法加载任何底层扩展 |
启动环境 (start.sh) |
包含 export PHPRC="$SCRIPT_DIR" |
缺少 export PHPRC |
就算放了 php.ini,libphp.so 也不会读取 |
底包动态库 (lib/) |
246 个 .so 文件(含 libcurl.so.4, libssl, libevent 等) |
仅 14 个基础系统库 | 扩展即使放入也会因缺失底层 .so 报错 |
| 源码隔离 | dist 内无任何 vendor/ 源码 |
把整个 vendor/ 错误拷入 dist/ |
冗余且容易触发 AOT 编译符号与动态源码冲突 |
| fast-route 处理 | functions.php 编入二进制内部 |
未编译,却在 main.stub 动态 require |
启动流程冗余脆弱 |
Important
- Builder 镜像重新打包与升级版本:
当前的打包机制是由 Docker 镜像中的
/entrypoint.sh负责收集动态库和组装dist。要使构建产物生成ext/、php.ini并补全lib/依赖库,必须更新webman-typephp/docker/entrypoint.sh并重新构建发布 builder 镜像(例如tinywan/typephp-webman-builder:v0.0.14)。 - Monolog 策略选择: 采用参考项目成熟的白名单机制,仅编译 Webman 必需的核心 Logger 与 Handler,确保不引入冷门扩展的 Handler 导致崩溃。
- 将
monolog的探测由目录探测调整为核心文件白名单(对齐参考项目project.linux.yml)。 - 将
vendor/nikic/fast-route/src/functions.php编入sources。 - 将默认并发编译
job参数从4调整为安全默认值或根据可用内存设置。
--- a/src/Compiler/ProjectGenerator.php
+++ b/src/Compiler/ProjectGenerator.php
@@ -52,6 +52,7 @@ class ProjectGenerator
'vendor/workerman/coroutine/src',
'vendor/psr',
+ 'vendor/nikic/fast-route/src/functions.php',
'vendor/nikic/fast-route/src/BadRouteException.php',
'vendor/nikic/fast-route/src/DataGenerator.php',
@@ -74,3 +75,28 @@
if (is_dir($this->basePath . '/vendor/monolog/monolog/src')) {
- $sources[] = 'vendor/monolog/monolog/src';
+ $monologSources = [
+ 'vendor/monolog/monolog/src/Monolog/Logger.php',
+ 'vendor/monolog/monolog/src/Monolog/LogRecord.php',
+ 'vendor/monolog/monolog/src/Monolog/ResettableInterface.php',
+ 'vendor/monolog/monolog/src/Monolog/DateTimeImmutable.php',
+ 'vendor/monolog/monolog/src/Monolog/ErrorHandler.php',
+ 'vendor/monolog/monolog/src/Monolog/Registry.php',
+ 'vendor/monolog/monolog/src/Monolog/Utils.php',
+ 'vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php',
+ 'vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php',
+ 'vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php',
+ 'vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/Handler.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php',
+ 'vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php',
+ 'vendor/monolog/monolog/src/Monolog/Processor',
+ ];
+ foreach ($monologSources as $source) {
+ if (file_exists($this->basePath . '/' . $source) || is_dir($this->basePath . '/' . $source)) {
+ $sources[] = $source;
+ }
+ }
}- 对齐
tinywan-typephp-webman/main.php,精简启动入口,去除已 AOT 编译文件的重复require_once。
- 停止错误复制
vendor目录: 删除将vendor/workerman、vendor/nikic等源代码复制到stage_dir/vendor的逻辑。 - 复制扩展模块 (
dist/ext): 从系统 PHP 扩展目录(php-config --extension-dir)提取.so扩展至$stage_dir/ext/。 - 生成自包含
php.ini: 写入配置并按顺序激活posix,pcntl,curl,pdo_mysql,mbstring,openssl,redis等扩展。 - 扩展依赖库扫描与
ldd补全 (dist/lib): 像参考项目的package.sh一样,不仅扫描webman-server.bin,还要扫描$stage_dir/ext/*.so,将扩展所依赖的libcurl.so.4等系统共享库全部追踪并复制到$stage_dir/lib/。 - 升级
start.sh: 加入export PHPRC="$app_dir"。
- 将默认镜像版本标签递增(如构建发布后升级为
v0.0.14)。
- 执行代码格式与规范分析:
composer check
- 在 Webman 测试项目中生成配置并检查:
执行
php webman typephp:package前,检查生成的.typephp/build/project.linux.yml中的sources是否包含完整的白名单且无粗暴的全量vendor/monolog/monolog/src。 - 构建测试与产物结构比对:
运行编译后,检查
dist/目录结构:- 必须存在
dist/ext/且包含curl.so - 必须存在
dist/php.ini且声明extension_dir="./ext"与extension=curl.so - 必须存在
dist/lib/libcurl.so.4 dist/根目录下不得有vendor/源码目录
- 必须存在
- 运行测试:
在 Linux 环境或容器内运行:
检查终端输出,确保无
cd dist && ./start.sh start
Undefined constant报错,正常输出 Workerman 监听信息。