mevdschee/phpfilemerger
Composer 安装命令:
composer create-project mevdschee/phpfilemerger
包简介
Intelligently merge PHP files and dependencies into a single file
README 文档
README
A CLI tool that merges a PHP entry point and all of its class dependencies into a single self-contained PHP file. It uses a proper AST parser (nikic/php-parser) rather than naive file concatenation, producing a correctly ordered, dependency-aware output file.
Blog: tqdev.com/2026-merge-php-projects-single-file
Use Case
If you maintain a PHP project that you want to distribute as a single file (e.g.
a single-file API or a standalone script), PHP File Merger automates the
process. It statically analyzes your code, resolves all
class dependencies via PSR-4/PSR-0 autoloading, sorts them in dependency order,
and writes a single merged .php file.
Requirements
- PHP 8.1 or higher
- Composer (for building from source)
Installation
Download the single-file build (recommended)
Download the latest phpfilemerger.php from the releases and run it directly:
php phpfilemerger.php merge src/index.php
Build from source
git clone https://github.com/yourname/phpfilemerger
cd phpfilemerger
composer install
./build.sh
This produces phpfilemerger.php in the project root. The build uses
phpfilemerger to merge its own sources, so there is no external build
dependency. build.sh is a thin wrapper around a single self-compilation
command, which you can also run directly:
php src/index.php merge src/index.php --output phpfilemerger.php
Run without building
composer install php src/index.php merge src/index.php
Usage
php phpfilemerger.php merge <entry> [options]
merge is the default command and can be omitted:
php phpfilemerger.php <entry> [options]
Arguments
| Argument | Required | Description |
|---|---|---|
entry |
Yes | Path to the PHP entry point file |
Options
| Option | Short | Default | Description |
|---|---|---|---|
--output |
-o |
<entry>.merged.php |
Output file path |
--project-root |
Auto-detected | Project root (directory containing composer.json) |
|
--vendor-dir |
<project-root>/vendor |
Vendor directory path | |
--exclude-entry |
false |
Exclude the entry point's procedural code from output (output is named <entry>.include.php by default) |
|
--indent |
4 |
Number of spaces used for indentation in the output |
The project root is auto-detected by walking up the directory tree from the
entry point looking for a composer.json file.
Examples
Merge src/index.php and all its dependencies into a single file:
php phpfilemerger.php merge src/index.php
# Output: src/index.merged.php
Specify a custom output path:
php phpfilemerger.php merge src/index.php --output dist/app.php
Produce an includeable library file (no entry-point code, only class definitions):
php phpfilemerger.php merge src/index.php --exclude-entry --output dist/lib.php
How It Works
- Parse: The entry point is parsed using
nikic/php-parser. All class references (extends,implements, traituse,new, type hints, attributes, etc.) are extracted. - Resolve: Each referenced class name is resolved to a file path using
PSR-4/PSR-0 mappings read from
composer.jsonand the Composer-generated autoload files invendor/composer/. - Build dependency graph: The tool recursively processes dependencies, building a graph of all required files.
- Sort: Files are sorted in topological order so that hard dependencies
(
extends,implements, traituse) are always placed before the classes that depend on them. - Merge: Each file is processed by the AST and its contents are emitted
into the output file, wrapped in an explicit
namespace { ... }block. The following transformations are applied automatically:declare(strict_types=1)declarations are stripped (they are illegal inside the bracketed namespace blocks, so the merged file runs without strict typing)require vendor/autoload.phpstatements are removed- Any
filesautoload entries from vendor packages (e.g. global helper functions) are inlined - Statically resolvable
require/includecalls whose path is built from__DIR__(e.g.require __DIR__ . '/bootstrap80.php') are inlined: the target is emitted once as a closure in its own namespace and the call site is rewritten to invoke it, preserving conditionals, return values andrequire_oncesemantics - Files that early-exit with a namespace-scope
return(common in polyfills) are wrapped in an immediately-invoked closure so thereturndoes not abort the whole merged file - Each included file is annotated with a
// file: relative/path.phpcomment
- Validate:
php -lis run on the output file to verify syntax.
What the output looks like
#!/usr/bin/env php <?php // Generated by PHP File Merger // file: vendor/example/package/src/Helper.php namespace Example\Package { function helperFunction() { ... } } // file: src/Model/Foo.php namespace MyApp\Model { class Foo { ... } } // file: src/index.php namespace { $app = new \MyApp\Model\Foo(); $app->run(); }
Limitations
- Dynamic class loading:
new $className()and similar dynamic patterns cannot be statically analyzed and will not be automatically included. - Multiple namespace blocks per file: files using more than one namespace
block may not be handled correctly. A dynamically-required file that mixes
namespaces is left as-is (its
requireis skipped with a warning) rather than inlined. include/requirestatements: calls whose path resolves statically from__DIR__are inlined. Anything dynamic (a variable path, a glob, a path that cannot be resolved at merge time) is skipped with a warning, since relative paths would break in the merged file.- Runtime
__DIR__/__FILE__resource access: only__DIR__used inside arequire/includeis handled. Code that uses__DIR__/__FILE__at runtime to reach non-PHP resource files (templates, data directories,.json/.distassets) cannot be bundled into a single file — those resources are not code. Such paths resolve relative to the merged file and will fail at runtime. For example, Symfony Console'scompletioncommand scans itsResources/directory this way, so merging an application that registers it will fail when that command is constructed. - Top-level
exit/die: a dependency file that callsexit/dieat namespace scope is skipped with a warning (it would abort the merged file). A top-levelreturn, by contrast, is now contained by wrapping the file body in a closure.
Development
# Run tests vendor/bin/phpunit # Build the single-file distributable ./build.sh
What about smartinus44/phpfilemerger?
The project smartinus44/phpfilemerger is no longer published, and its exact behavior is not documented, but this project aims to replace it. The code is not a fork of smartinus44/phpfilemerger, but deduced from the code written for PHP‑CRUD‑API, a project that flattens multiple PHP source files into a single distributable API script.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 9
- 点击次数: 4
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-12