# php-scoper: Renaming Namespaces So Two PHARs Can Coexist

> PHP-Scoper is an MIT licensed tool that prefixes every namespace in a codebase and its vendor directory so the bundled code cannot collide with the versions the host project loaded. It suits anyone shipping a PHAR that carries its own dependencies and has to run beside code with different versions of the same packages.

**humbug/php-scoper** — 🔨 Prefixes all PHP namespaces in a file/directory to isolate the code bundled in PHARs.

- Repository: https://github.com/humbug/php-scoper
- Stars: 811 · Forks: 78
- Language: PHP
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/humbug-php-scoper

## The conflict PHP-Scoper exists to prevent

PHP-Scoper moves any body of code, including all its dependencies such as vendor directories, to a new and distinct namespace. The goal is stated as ensuring that all the code of a project lies in a distinct PHP namespace, and the reason it matters is PHAR packaging. A PHAR that bundles its own vendor dependencies and then loads or executes code from arbitrary PHP projects with similar dependencies has a specific failure mode: when a package, possibly in a different version, is found both in the PHAR and in the executed code, the one from the PHAR wins. That PHAR therefore risks conflicts between its bundled dependencies and those of the project it interacts with, and because the versions mismatch or are unsupported, the resulting issues are very difficult to debug. Namespacing the bundled code removes the ambiguity at the source rather than papering over it at load time.

## What gets prefixed and what gets copied untouched

Prefixing is limited to PHP files and scripts, and other files are copied unchanged, with the exception of certain Composer-related files, which are also scoped. That distinction matters for build size and for assets, since images, templates and configuration keep working while the code around them moves. The tool copies the code to a new location during prefixing and leaves your original code untouched, with `./build` as the default output directory. The default prefix is random, generated per run, and the `--prefix` option sets it explicitly while `--output-dir` changes the destination. When automating builds, `--force` overwrites existing code in the output directory without a confirmation prompt, which is the flag you need in a non-interactive pipeline.

## The add-prefix command and what it writes

The usage section is one command.

```bash
php-scoper add-prefix
```

That prefixes all the relevant namespaces of the code found in the current working directory, and the prefixed files are written to a `build` directory, ready to be packed into a PHAR. There is a warning attached to it: if you rely on Composer for autoloading, you must dump the autoloader again after prefixing the files. The README points at PHP-Scoper's own build step in the Makefile as the concrete example to follow, particularly if you use Composer, since there are steps to consider both before and after running the tool. The basic form of the command, with default options, run from the project root, is also spelled out.

```bash
bin/php-scoper add-prefix
```

## Building the PHAR without Box

If you use Box to build your PHAR, the recommendation is to rely on its PHP-Scoper integration, since Box takes care of most of the process and you should only need to adjust the PHP-Scoper configuration. Without Box there are two steps. The first is preparing the vendors.

```bash
composer install --no-dev --prefer-dist
```

Skipping development dependencies saves time during scoping, because unnecessary files are not processed. The second step is running the tool itself, and then regenerating the Composer autoloader so that everything works as expected.

```bash
composer dump-autoload --working-dir build --classmap-authoritative
```

That classmap-authoritative flag is the detail to notice. After prefixing, the class names in the build directory no longer match the ones the original autoloader knows about, so the autoloader has to be rebuilt against the scoped code, and an authoritative classmap avoids the fallback lookups that would otherwise try paths that no longer exist.

## The limitations page is the honest part of the documentation

The table of contents lists a long limitations section, and that list is the most useful thing in the project for anyone evaluating it. The documented weak spots are dynamic symbols, date symbols, heredoc values, callables and string values, which all fail for the same reason: a name that exists only as text cannot be rewritten by a tool that understands PHP syntax. There are also limitations around native functions and constants shadowing, the Composer autoloader, Composer plugins, partial support for PSR-0, and problems with exposing or excluding traits and enums. The separate entry about declaring a custom namespaced function and the `function_exists()` check is the sharpest example of the category, since a namespaced function that shadows a global one changes what `function_exists()` returns depending on which namespace the call happens in.

## Exposed symbols and the escape hatch for shared APIs

Not everything should be prefixed, and the configuration gives you control over that. There are separate sections for excluded files, excluded symbols, excluding namespaces, and exposed symbols, with exposed symbols broken down further into exposing namespaces, classes, functions and constants. The idea is that a PHAR which needs to interoperate with code outside itself can leave specific symbols under their original names, so both sides agree on what the Symfony console Application class means while everything else stays isolated. The architecture section describes exposed symbols and the scoper autoload as the mechanism, and the further reading section covers how to deal with unknown third-party symbols, autoload aliases, class aliases and function aliases, plus dedicated pages for Laravel, Symfony and WordPress support. In practice the exposed symbol list is the file where the real work of a scoping setup lives.

## The config file, the Docker image and the four install routes

Configuration is documented in its own pages covering the prefix, the PHP version, the output directory, finders and paths, patchers, and the exclusion and exposure lists. The repository carries a `scoper.inc.php` at the root, which is the configuration for scoping PHP-Scoper itself, and a `box.json.dist` for Box. Installation is documented in four ways, as a PHAR, through Phive, through Composer and through Docker. The Dockerfile shows the Docker route: it starts from `php:8.2-cli-alpine`, installs the zlib, phar, sodium, tokenizer and filter extensions using the mlocati extension installer, copies `bin/php-scoper.phar` into the image, and sets that PHAR as the entrypoint. That is a lean image with only the extensions the tool actually needs, which is what you want in a build pipeline.

## Maintenance, tooling and how the project is checked

The repository is not archived and the last push was on 2026-10-20, with release 0.18.20 on 2026-10-08 following 0.18.19 on 2026-03-02 and 0.18.18 on 2025-10-15. The licence is MIT. The development tooling in the Makefile is worth a look because it shows what the project checks itself with: PHPUnit for tests with coverage via XDEBUG_MODE, PHPStan with separate configurations for source and tests, PHP CS Fixer, Rector for automated refactoring, and Infection for mutation testing, which is an unusually strict choice for a code transformation tool because the transform itself has to be trustworthy. There is also a composer-root-version-checker and a `vendor-hotfix/` directory, a build directory, a `fixtures/` directory for tests, and `_specs/` alongside `specs/`. The Makefile exposes a `check` target that runs the composer version lint, the code style check, an autoreview, the tests and the composer root version check in sequence.

## Conclusion

php-scoper fits a team shipping a PHAR that bundles its own dependencies and runs inside a host project whose versions may differ, which is the case where a class name collision is otherwise hard to debug. It is the wrong choice if your project does not bundle dependencies, since the whole mechanism is pointless without that conflict, and it is the wrong choice if your code resolves symbols dynamically at runtime. Before you adopt it, read the limitations page, because dynamic symbols, string values and the Composer autoloader are all cases the tool documents as hard.

## FAQ

### What does PHP-Scoper actually do to my code?

It prefixes all relevant namespaces of the code in the current working directory, including vendor directories, and writes the prefixed files to a build directory, leaving the original code untouched. Only PHP files and scripts are prefixed, with certain Composer-related files also scoped.

### Why do I need to dump the Composer autoloader after prefixing?

Because the class names in the build directory have changed, so the existing autoloader no longer resolves them. The documented step is composer dump-autoload --working-dir build --classmap-authoritative, and the project warns that skipping it breaks autoloading.

### What are the known limitations of PHP-Scoper?

The documentation lists dynamic symbols, date symbols, heredoc values, callables, string values, native function and constant shadowing, the Composer autoloader, Composer plugins, partial PSR-0 support, and exposing or excluding traits and enums, because names that exist only as text cannot be rewritten by a syntax-aware tool.

### How do I keep some classes unprefixed?

The configuration has separate sections for excluded files, excluded symbols, excluded namespaces and exposed symbols, with exposed symbols broken down into namespaces, classes, functions and constants. The autoload aliases and class alias pages in the further reading section cover the cases where the original name has to stay visible.

### How is PHP-Scoper installed and how do I run it?

It installs as a PHAR, through Phive, through Composer or through Docker, where the image is based on php:8.2-cli-alpine with the phar, sodium, tokenizer and filter extensions and the PHAR as its entrypoint. The main command is php-scoper add-prefix, run from the project root.

## Sources

- [humbug/php-scoper on GitHub](https://github.com/humbug/php-scoper)
- [Issues](https://github.com/humbug/php-scoper/issues)
- [License: MIT](https://github.com/humbug/php-scoper/blob/main/LICENSE)
- [README](https://github.com/humbug/php-scoper/blob/main/README.md)
- [Releases](https://github.com/humbug/php-scoper/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/humbug-php-scoper
