In the articles Managing your dependencies in PHP and Create and deploy secure PHARs I covered some use cases for PHARs as well as introduced a few tools making it easier to work with them.

However, I think the tooling for PHARs could be improved with:

Isolating dependencies (see more about the issue here).

Installing, updating and keeping track of PHARs in a secure fashion is still not straightforward enough.

The overall workflow is under documented and far from being optimal.

In this article, I’ll try to cover those points

So in this article, I’ll try to cover all the points above and explain what I have in mind. If the project picks your interest, then you should get a clear idea of what the plan is and otherwise you can always ping me :)

The whole roadmap is accessible at the box’s Humbug fork project.

PHP-Scoper is an ambitious project. It aims at tackling the first issue regarding the dependencies isolation. In theory it’s relatively simple: change the namespace of the bundled code to avoid any conflict.

At the time of writing, PHP-Scoper is successfully being used on schema-generator and itself. It’s still relatively young though so a few issues are expected to arise. The main remaining issues are:

Add a box integration: this requires to create a plugin for Box as well as switching the box configuration which is in a JSON format right now into a PHP one.

Fix the prefixing of classes belonging to the global namespace: #117 and #135.

Add PSR-0 support.

Once this project is done, this would be extremely useful for projects like PHPUnit. Indeed, a test framework such as PHPUnit requires a lot of dependencies which can be an issue. Instead of importing phpunit/phpunit as a dev dependency which includes:

Test cases and suites to write the tests

Assertions

The engine which is what is used to execute your tests

A lot of those dependencies are used for the engine which you as a consumer don’t need. With PHP-Scoper, a lightweight library containing only the test cases and assertions could be provided. Then to execute the tests, you could use the PHAR and as a result this would greatly reduce the number of dependencies that you would require to use PHPUnit.

Box is an application to build and manage PHARs. The box project itself is at the same time quite good and quite bad. The good part is that it’s working relatively well and is very stable. The bad parts are: a lack of maintenance/support, heavy use of deprecated libraries, missing some features.

As I don’t have control on that project, I forked it under the Humbug umbrella and I hope at some point this could be merged back to the main repository.

Over the last few months, I did some refactoring which tackles the worst part of it:

Update the dependencies and remove the usage of the deprecated ones

Merge a few repositories (the box project and the box library among others) to ease the management

Rework some tests & tools to make things easier to start and maintain

What is missing from it now is the juicy parts.

As explained in #14, once you start signing your PHAR files, this is becoming really inconvenient for the contributors as this requires them to create a private key as well. It’s possible to avoid that with a little trick (see the issue for more about it) but I believe this could be simpler.

Also to encourage people to sign their PHARs, a warning could be displayed when a non-signed PHAR is being used.

As explained in #13, unlike when installing a dependency with Composer, no constraint check is done when installing/using a PHAR. It can be done in an installer but then it’s easy to miss it if downloading the PHAR directly, keeping the PHAR around and updating it or copying it from somewhere.

An attempt has been made in PHP-Scoper based on Symfony’s requirement checker. It however has a few drawbacks:

It is limited to checking extensions and the PHP platform (which can be fine) but don’t take into consideration polyfills. A possible solution could be to look if a polyfill is included as well and ignore the extension requirement if it is.

As of now it only checks the project root composer.json and doesn't account for the dependencies composer.json files, which is incomplete. If for example you require ext-xml in your composer.json and one of your dependencies requires ext-pdo , the first one will be properly checked but not the second.

and doesn't account for the dependencies files, which is incomplete. If for example you require in your and one of your dependencies requires , the first one will be properly checked but not the second. This checker needs to run in an environment in which the application will not be able to. For example in the case of PHP-Scoper, it needs to be compatible with PHP 5.6 (even though PHP-Scoper requires PHP 7.1) to be able to provide a nice error message when running on PHP 5.6. This is also true for extensions and it results in a lot of boiler template. I didn’t invest much time on it but I think this could be greatly simplified.

See #12 for the GitHub issue.

At the entry point of the application (bundled in the PHAR or not), the autoloader needs to be required. Depending of if you are inside the PHAR, inside the project or installed it as a global or regular dependency, the location will differ.

This is certainly not the hardest issue, but I think it would be nice to have one bullet-proof script which anyone could use as a reference instead of taking the risk to forget one case.

There is two kind of optimisations that can be provided.

The first one is about the speed of the PHAR building itself. The way this is done at the time of writing is rather straightforward: retrieve all the files to add to the PHAR and process (compression for example) them one by one. There is a lot of optimisation that could be done by parallelising this work, especially once a PHP-Scoper integration will be added. Indeed if compressing a file can be relatively fast in which case parallelisation won’t offer much, scoping a file is another story and it’s much slower.

A second kind of optimisation is for the packaged application, i.e. the PHAR itself. Here is the list of the possible optimisations (some are already available):

Reduce the number of files: get rid of useless files like README.md , doc, tests etc as well as development dependencies. Getting rid of files can easily be done via the exclude pattern in the box configuration and excluding dev dependencies can be done thanks to composer --no-dev option when installing them with composer install .

, doc, tests etc as well as development dependencies. Getting rid of files can easily be done via the exclude pattern in the box configuration and excluding dev dependencies can be done thanks to composer option when installing them with . Make use of compressors: there is currently already a JSON, PHP and JavaScript compressor available out of the box with Box. Whilst I think the PHP one could be enhanced, this is already a good base and depending of the use case one could easily add a new compressor. On a quick test, I noticed a 30% size decrease of the PHAR with compressors alone.

Compress the PHAR: there is several compressing formats like GZ and BZ2 available which reduce the PHAR size up to 80%.

and available which reduce the PHAR size up to 80%. Prefixing: During the prefixing process, PHP-Scoper transforms as much as possible calls into fully qualified calls which makes it faster as either help opcache or avoid an extra autoloading step (as there is no longer any guess work to do to know if a function is from the current namespace or from the global namespace). See Roave’s FunctionFQNReplace for more.

As of now Humbug’s PharUpdater is the most popular library for providing a PHAR update command. However as mentioned in #53, I can’t help but to find too tedious to use. There is too much disparity in its usage even for basic cases. I’m sure there is a way to make it easier and provide a more consistent behaviour across PHARs.

As mentioned on GitHub on #53 and explained here, there is two “good” ways to do it:

Using an installer

Using PHIVE

I personally didn’t make my mind yet about PHIVE. Maybe it’s the way to go and it’s only missing a few features and a bit of UX love.

The alternative which is using an installer, is so far too tedious in my opinion: there is no idiomatic way to do it. It’s often an in-house long script like you can see with Composer, Box or Puli. Those scripts are verbose, repetitive and error prone. They are in my opinion not viable as they are especially since they are critical from a security point of view.

As the new version of Box is being pushed forward, it is also good to help the existing projects and do a health check on their practice to help them to make it easier to build, optimize and maintain PHARs.

A list is provided in #19 which includes:

The tooling for building and managing PHARs is already here. PHP-Scoper among others is a good example of how to use all the tools mentioned above. They work, it’s only missing a few features to make it easier to use and maintain.

This is a significant work nonetheless so I’m looking for help to speed things up. You can get started by any of the issues above, in the GitHub board or simply by pinging me to show your interest!