能被composer create-project正确识别并复用的模板,核心在于type字段必须显式设为"project",同时不能有未解决的依赖冲突或语法错误。其他字段如name、description主要是为了人类可读和 Packagist 展示,并非运行必需。

composer.json 里怎么写才能当模板用
说到底,要让一个项目被 composer create-project 正确识别并复用,type 字段必须写成 "project" ——哪怕这个模板只是扔在本地的临时项目。否则,create-project 很可能会跳过自动加载初始化或脚本执行,到时候你才发现白忙一场。
实际操作中,有几个细节值得注意:
type必须显式声明为"project",别指望它能被自动推断。autoload要提前配好,比如"psr-4": {"App\\": "src/"}。如果模板里没配,新项目生成后还得手动补上,否则vendor/autoload.php加载不到你自己定义的类。- 不要在模板里写死具体版本号。比如
"php": "^8.1"可以,但"monolog/monolog": "2.13.0"就太僵硬了。用"^2.13"或"^2.0"更利于下游项目灵活升级。 - 如果模板里含有占位符(比如
MyVendor\MyApp),建议在scripts里配置post-create-project-cmd去自动替换,而不是靠人工挨个改。
post-create-project-cmd 脚本为什么经常不执行
这个钩子只会在 composer create-project 过程中触发一次,而且前提是模板项目已经成功克隆、composer install 完成、autoload 生成完毕。多数情况下,脚本不执行并不是因为代码写错了,而是前置条件没满足。
几个常见陷阱:
- 脚本路径必须可执行。比如写了
"@php ./bin/init.php",那bin/init.php文件得存在,且开头要有#!/usr/bin/env php,或者确保php命令能访问到它。 - 不要依赖
$argv或对当前工作目录做假设。create-project会在目标目录下运行脚本,但环境变量有限。推荐用getcwd()明确获取项目根路径。 - 钩子执行时,
vendor/已经存在,但 autoload 可能还没完全生成。所以不要在脚本里直接new某个 vendor 类。清理 .git 目录、替换命名空间、生成 .env 文件这类操作是安全的。 - 调试时加日志:在脚本开头写
file_put_contents('init.log', date('c') . "\n", FILE_APPEND);,比只看终端输出更可靠。
能不能让模板自动适配不同 PHP 版本
模板本身没办法“自动适配”,但可以通过 config.platform.php 锁定构建时的平台版本,避免在高版本 PHP 环境里装上低版本不兼容的扩展依赖。
具体做法:
- 在模板的
composer.json里加上"config": {"platform": {"php": "8.1.0"}}。这样即使你在 PHP 8.3 环境里跑create-project,Composer 也会按 8.1 的约束来选包,防止装上只支持 8.2+ 的扩展。 - 别滥用
platform:它只影响依赖解析,不改变运行时行为。如果你的模板代码里用了str_contains(),那 PHP 低于 8.0 依然会报错,该写的版本检查还是得写。 - 真正需要多版本兼容时,靠
require中的版本约束更直接。比如"ext-json": "*"比写死"ext-json": "^1.0"更稳妥。
为什么用 composer create-project 生成的项目 vendor/autoload.php 不生效
大概率是模板里的 autoload 配置没生效,或者新项目没有重新 dump autoload。create-project 不会自动执行 composer dump-autoload,尤其当模板里没设 autoload-dev 或 PSR-4 映射路径写错时,vendor/autoload.php 就只是个空壳。
几个检查点:
- 检查模板
composer.json中autoload的路径是否相对于模板根目录。比如写"src/"是对的,但"./src/"或"src"(缺少末尾斜杠)都会让 Composer 忽略整条规则。 - 生成新项目后,立刻进入目录执行
composer dump-autoload -o,确认没有报错。再测试require 'vendor/autoload.php'; new App\SomeClass();,看能否正常加载。 - 如果用了
psr-4,命名空间末尾的反斜杠必须双写为\\。JSON 里应该写成"App\\": "src/",如果写成"App": "src/",Composer 会直接跳过这条规则,解析失败。
一句话总结:模板不是越“完整”越好,关键路径要通、钩子要稳、autoload 要准。很多问题其实出在 copy-paste 时带入了不可见字符,或者以为 JSON 允许尾随逗号——这两点在模板场景下尤其致命。