maks-rafalko / box

πŸ“¦πŸš€ Fast, zero config application bundler with PHARs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Package version Travis Build Status Scrutinizer Code Quality Slack License

Fork of the unmaintained box2 project. This project needs your help!

Roadmap:

Goal

The Box application simplifies the PHAR building process. Out of the box (no pun intended), the application can do many great things:

  • ⚑ Fast application bundling
  • πŸ”¨ PHAR isolation
  • βš™οΈ Zero configuration by default
  • πŸš” Requirements checker
  • 🚨 Friendly error logging experience
  • πŸ” Retrieve information about the PHAR extension or a PHAR file and its contents
  • πŸ•΅οΈβ€β™€οΈ Verify the signature of an existing PHAR
  • πŸ“ Use Git tags and short commit hashes for versioning

Table of Contents

  1. Installation
    1. PHAR (preferred but NOT SUPPORTED YET)
    2. Composer
  2. Creating a PHAR
  3. Configuration
    1. Base path
    2. Main
    3. Output
    4. Permissions
    5. Check requirements
    6. Including files
      1. Files (files and files-bin)
      2. Directories (directories and directories-bin)
      3. Finder (finder and finder-bin)
      4. Blacklist (blacklist)
    7. Stub
      1. Stub (stub)
      2. Alias (alias)
      3. Shebang (shebang)
      4. Banner (banner)
      5. Banner file (banner-file)
    8. Dumping the Composer autoloader (dump-autoload)
    9. Compactors (compactors)
    10. Compression algorithm (compression)
    11. Signing algorithm (algorithm)
  4. Requirements checker
    1. Usage
    2. Polyfills
  5. Optimize your PHAR
    1. Review your files
    2. Compress your PHAR
    3. Optimize your code
  6. PHAR code isolation
    1. Why/Explanation
    2. Isolating the PHAR
    3. Debugging the scoping
  7. Contributing
  8. Upgrade
  9. Backward Compatibility Promise (BCP)
  10. Credits

Installation

PHAR (preferred but NOT SUPPORTED YET)

Coming soon.

The preferred method of installation is to use the Box PHAR, which can be downloaded from the most recent Github Release. Subsequent updates can be downloaded by running:

box self-update

As the PHAR is signed, you should also download the matching box.phar.pubkey to the same location. If you rename box.phar to box, you should also rename box.phar.pubkey to box.pubkey.

Composer

You can install Box with Composer:

composer global require humbug/box:^3.0@alpha

If you cannot install it because of a dependency conflict or you prefer to install it for your project, we recommend you to take a look at bamarni/composer-bin-plugin. Example:

composer require --dev bamarni/composer-bin-plugin
composer bin box require --dev humbug/box:^3.0@alpha

Keep in mind however that this library is not designed to be extended.

Creating a PHAR

Creating a PHAR should be as simple as running box compile (no config required!). It will however assume some defaults that you might want to change. Box will by default be looking in order for the files box.json and box.json.dist in the current working directory. A basic configuration could be for example changing the PHAR permissions:

{
    "chmod": "0755"
}

You can then find more advanced configuration settings in the configuration documentation. For more information on which command or options is available, you can run:

box help

Requirements checker

Usage

Unlike when installing a library with Composer, no constraint check is done by default with a PHAR. As a result if you are using a PHAR of an application compatible with PHP 7.2 in PHP 7.0 or a PHP environment which does not have a required extension, it will simply break with a non-friendly error.

By default, when building your PHAR with Box, Box will look up for the PHP versions and extensions required to execute your application according to your composer.json and composer.lock files and ship a micro (>300KB uncompressed and >40KB compressed) requirements checker which will be executed when starting your PHAR.

The following are screenshots of the output when an error occurs (left) in a non-quiet verbosity and when all requirements are passing on the right in debug verbosity.

Polyfills

Box supports the following polyfills:

Functions requirements/polyfills are not supported at the moment, see #131.

Optimize your PHAR

Review your files

By default Box try to be smart about which files are required and will attempt to use only the necessary files. You can list the files of your PHAR with the box info --list command. It is however possible you want a finer control in which case you can adapt the included files thanks to the configuration options.

All the files in the PHAR are loaded in-memory when executing a PHAR. As a result, the more content there is to load, the bigger the overhead will be and unlike your regular application, a PHAR will not benefit from the opcache optimisations. The difference should however be minimal unless you have dozens of thousands of files in which case you might either accept it, consider an alternative or contribute to the PHAR extension in order to optimise it.

Compress your PHAR

You can also greatly enhance the size of your PHAR by compressing it:

  • The compression algorithm setting. It is very efficient, however note that a compressed PHAR requires the zip PHP extension and has a (micro) overhead since PHP needs to uncompress the archive before using it
  • Compactors can also help to compress some contents for example by removing the unnecessary comments and spaces in PHP and JSON files.

Optimize your code

Another code performance optimisation that can be done is always use fully qualified symbols or use statements. For example the following:

<?php

namespace Acme;

use class stdClass;
use const BAR;
use function foo;

new stdClass();
foo(BAR);

Will be more performant than:

<?php

namespace Acme;

use class stdClass;

new stdClass();
foo(BAR);

Indeed in the second case, PHP is unable to know from where foo or BAR comes from. So it will first try to find \Acme\foo and \Acme\BAR and if not found will fallback to \foo and BAR. This fallback lookup creates a minor overhead. Besides some functions such as count are optimised by opcache so using a fully qualified call \count or importing it via a use statement use function count will be even more optimised.

However you may not want to care and change your code for such micro optimisations. But if you do, know that isolating your PHAR code will transform every call into a fully qualified call whenever possible enabling that optimisation for your PHAR.

PHAR code isolation

Why/Explanation

When bundling the code in a PHAR, it is equivalent to compacting all the code in a single file. However the code does not go through any transformations, meaning the code in the PHAR remains unchanged. This, when the PHAR loads external code, can lead to dependency conflicts. To illustrate that issue with an example: you are building a console application myapp.phar which relies on the library Symfony YAML 2.8.0 which execute a given PHP script.

# Usage of the application we are building
myapp.phar myscript.php

For the sake of the example, myapp.phar is using Composer and loads the YAML component right away when starting, i.e. when running myapp.phar, the class Symfony\Yaml\Yaml from the PHAR is going to be loaded. Now what myapp.phar is actually going to do is scan the whole file given, and do some reflection work on each classes found. I.e. for each class $class found, it will do new \ReflectionClass($class).

Now if myscript.php is using the Symfony YAML 4.0.0 component with some new features added in 4.0.0 that are non-existent in 2.8.0, when doing new \ReflectionClass('Symfony\Yaml\Yaml'), the class Symfony\Yaml\Yaml will be loaded (yes, doing reflection on a class loads it!). BUT, it turns out the class Symfony\Yaml\Yaml is already loaded: not the 4.0.0 from myscript.php but the one from the PHAR (2.8.0). So any information you will get will be from the wrong class!

Is this really an issue? The answer is it depends. Here as a few real life example where this is an issue:

  • A static analysis tool like PHPStan
  • A test framework like PHPUnit
  • A quality analysis tool like SensioLabsInsight which executes arbitrary code (e.g. to check) that the application is booting
  • A piece of code that can be mixed with any code, such as a Wordpress plugin

Isolating the PHAR

Box provides an integration with PHP-Scoper. To use it, enable the KevinGH\Box\Compactor\PhpScoper compactor.

If you need an extra configuration for PHP-Scoper, you can create a scoper.inc.php file as per the documentation. The only difference is that you can ignore the finders setting as the files to scope are already collected by Box.

And that's it!

Warning: keep in mind however that scoping is a very brittle process due to the nature of PHP. As such you will likely need some adjustments in your code or the configuration.

Debugging the scoping

As mentioned above, unless you have a very boring and predictable code (which is a good thing), due to how dynamic PHP is, scoping will almost guaranteed never work on the first and will require adjustments. To help with the process, there is two recommendations:

  • Have an end-to-end test for your application. On in which you can easily swap from your regular binary, the PHAR and the isolated PHAR. This will help to identify at which test there is an issue besides being able to easily guarantee your application, shipped as a PHAR or not, is somewhat working.
  • Make use of Box --debug option in the compile command. It dumps the code added to the PHAR in a .box-dump directory. This allows you to more easily inspect, alter and test the code shipped in the PHAR. This way, you can make sure the code shipped is working before worrying aboutwhetherr that code is going to work inside a PHAR.

Contributing

The project provides a Makefile in which the most common commands have been registered such as fixing the coding style or running the test.

make

Upgrade

Check the upgrade guide.

Backward Compatibility Promise (BCP)

The policy is for the major part following the same as [Symfony's one][symfony-bc-policy]. Note that the code marked as @private or @internal are excluded from the BCP.

Credits

Project originally created by: Kevin Herrera (@kherge) which has now been moved under the Humbug umbrella.

About

πŸ“¦πŸš€ Fast, zero config application bundler with PHARs.

License:MIT License


Languages

Language:PHP 98.9%Language:Makefile 1.0%Language:Shell 0.1%Language:Batchfile 0.0%