Stars: 640
Forks: 94
Pull Requests: 612
Issues: 231
Watchers: 11
Last Updated: 2023-06-26 14:29:26
🔨 Prefixes all PHP namespaces in a file/directory to isolate the code bundled in PHARs.
License: MIT License
Languages: PHP, Makefile, Smarty, Vue, Shell, Blade
PHP-Scoper is a tool which essentially moves any body of code, including all dependencies such as vendor directories, to a new and distinct namespace.
PHP-Scoper's goal is to make sure that all code for a project lies in a distinct PHP namespace. This is necessary, for example, when building PHARs that:
When a package (of possibly different versions) exists, and is found in both a PHAR and the executed code, the one from the PHAR will be used. This means these PHARs run the risk of raising conflicts between their bundled vendors and the vendors of the project they are interacting with, leading to issues that are potentially very difficult to debug due to dissimilar or unsupported package versions.
php-scoper add-prefix
This will prefix all relevant namespaces in code found in the current working
directory. The prefixed files will be accessible in a build
folder. You can
then use the prefixed code to build your PHAR.
Warning: After prefixing the files, if you are relying on Composer for the auto-loading, dumping the autoloader again is required.
For a more concrete example, you can take a look at PHP-Scoper's build step in Makefile, especially if you are using Composer as there are steps both before and after running PHP-Scoper to consider.
Refer to TBD for an in-depth look at scoping and building a PHAR taken from PHP-Scoper's makefile.
If you are using Box to build your PHAR, you can use the existing PHP-Scoper integration. Box will take care of most of the things for you so you should only have to adjust the PHP-Scoper configuration to your needs.
Assuming you do not need any development dependencies, run:
composer install --no-dev --prefer-dist
This will allow you to save time in the scoping process by not processing unnecessary files.
PHP-Scoper copies code to a new location during prefixing, leaving your original
code untouched. The default location is ./build
. You can change the default
location using the --output-dir
option. By default, it also generates a random
prefix string. You can set a specific prefix string using the --prefix
option.
If automating builds, you can set the --force
option to overwrite any code
existing in the output directory without being asked to confirm.
Onto the basic command assuming default options from your project's root directory:
bin/php-scoper add-prefix
As there are no path arguments, the current working directory will be scoped to
./build
in its entirety. Of course, actual prefixing is limited to PHP files,
or PHP scripts. Other files are copied unchanged, though we also need to scope
certain Composer related files.
Speaking of scoping Composer related files... The next step is to dump the Composer autoloader if we depend on it, so everything works as expected:
composer dump-autoload --working-dir build --classmap-authoritative
There is 3 things to manage when dealing with isolated PHARs:
realpath()
which
will no longer work for the files within the PHAR since the paths are not
virtual.composer.lock
or you always ship your application with
up-to-date dependencies? The latter, although more ideal, will by design
result in more brittleness as any new release from a dependency may break
something (although the changes may be SemVer compliant, we are dealing with
PHARs and isolated code)As a result, you should have end-to-end tests for your (at the minimum) your released PHAR.
Since dealing with the 3 issues mentioned above at once can be tedious, it is highly recommended having several tests for each step.
For example, you can have a test for both your non-isolated PHAR and your isolated PHAR, this way you will know which step is causing an issue. If the isolated PHAR is not working, you can try to test the isolated code directly outside the PHAR to make sure the scoping process is not the issue.
To check if the isolated code is working correctly, you have a number of solutions:
build
directory. Do not forget that
you need to dump the Composer autoloader for the isolated code to work!.--debug
option from the compile
command in order to have the code shipped in the PHAR dumped in the .box
directory.Phar::extractTo()
method.Also take into consideration that bundling code in a PHAR is not guaranteed to work out of the box either. Indeed there is a number of things such as
For this reason, you should also h
Project originally created by: Bernhard Schussek (@webmozart) which has now been moved under the Humbug umbrella.