I wrote phpfilemerger, a small CLI tool that takes a PHP entry point and all of its class dependencies and produces a single self-contained PHP file. It uses an AST parser to resolve dependencies properly, so the output is ordered and ready to run.

Use case: PHP-CRUD-API

I maintain a PHP project that is distributes as a single file (PHP-CRUD-API) and phpfilemerger automates the process of building. It produces that one-file distribution, keeping class order and namespaces intact so the merged file works just like the original project. It statically analyzes your codebase using PSR-4/PSR-0 mappings and inlines all dependencies in the correct order.

Why not PHAR?

PHAR archives can bundle code, autoloaders and metadata and are generally a more robust single-file format. They do what phpfilemerger does, but better. However, PHAR execution is frequently disabled or restricted on web hosting. The phar stream wrapper may be turned off and/or execution of PHAR archives is blocked for security reasons. Using phpfilemerger allows you to work around these restrictions. It provides you the convenience of single file deployment whenever PHAR is not an option.

Note: A less elegant way to work around the PHAR execution limitation is pharscript that creates a PHP wrapper script that bootstraps an embedded PHAR archive. See: https://github.com/mevdschee/pharscript

How it works

  1. Parse the entry point with nikic/php-parser and extract all class references (extends, implements, trait use, type hints, new, etc.).
  2. Resolve class names to files using Composer autoload mappings and vendor/composer metadata.
  3. Build a dependency graph and topologically sort files so dependencies come before dependents.
  4. Emit a single output file with declare(strict_types=1) once, inlined vendor files entries, and per-file // file: annotations.
  5. Validate the generated file with php -l.

Examples

Merge src/index.php and all its dependencies into one file:

php phpfilemerger.phar merge src/index.php

Produce an includeable library (no entry logic):

php phpfilemerger.phar merge src/index.php --exclude-entry --output dist/lib.php

This can be used to include complex dependencies.

Limitations

Where PHAR archives can contain more or less any PHP project, phpfilemerger expects projects to be prepared with merging in mind. That usually means keeping class declarations and procedural bootstrap code separate, using PSR-style autoloading only, avoid usage of include/require and don’t do clever top-level return/exit/die tricks. These constraints do not conflict with common best practices for well-structured PHP libraries, but are a strict requirement for producing a merged single-file output with phpfilemerger.

  • Dynamic class loadingnew $className() and similar dynamic patterns cannot be statically analyzed and will not be automatically included.
  • Multiple namespaces — files using more than one namespace block may not be handled correctly.
  • File inclusions — any include/require other than vendor/autoload.php will trigger a warning and be skipped, since relative paths would break in the merged file.
  • Top-level returns — these are disallowed in dependency files (they would abort execution of the entire merged file) and will cause an error.

Self compilation

Note that phpfilemerger project itself cannot be compiled into a single-file output (yet). The essential nikic/php-parser package uses a lot of include/require and even contains a top-level return. Attempting to merge the tool’s own source results in errors telling you which files offend the rules:

git clone https://github.com/mevdschee/phpfilemerger.git
cd phpfilemerger
composer install
php src/index.php merge src/index.php

This show that some complex projects are not easily turned into a single PHP file with this tool. If you want to help improve this tool, this is a great place to start!

See: https://github.com/mevdschee/phpfilemerger

Enjoy!