php-makephar/doc/PHAR-PLUGINS.md

2.5 KiB

Plugins in Phar Archives

This is a short guide on how to create single-file portable plugins using MakePhar.

The workflow

  1. Your application should export functions that can be called by the plugin on load, such as myapp_plugin_register in the example below.
  2. Locate the .phar plugins to load, and @include them one at a time.
  3. Process the plugins etc that has been registered from the successfully loaded .phar libraries.

Example files

src/plugin.php

<?php

// Prevent standalone use, as it doesn't make sense
if (!is_callable('myapp_plugin_register')) {
    error_log("This is a plugin for MyApp and can't be used standalone");
    exit(1);
}

// Register the plugin
myapp_plugin_register(new MyPlugin\MyPlugin());

composer.json

{
    "autoload": {
        "files": [ "src/plugin.php" ],
        "psr-4": { "MyPlugin\\":"src/" }
    }
}

makephar.sdl

phar "myplugin.phar" {
    library;
    include {
        dir "src";
        dir "vendor";
    }
    exclude {
        dir ".git";
    }
}

Notes and Considerations

  • Try not to bundle unneccesary or duplicate dependencies using composer. It is possible to include multiple composer autoload.php files (as is done when including the phar libraries) but effectively only the first matching loader will be used. Thus, if you have required a library in the plugin that is also present in the main application, the main version will be loaded rather than the plugin version.

Problems and Solutions

Getting the directory of the running phar

You can get the path of the command invoked using $_SERVER['SCRIPT_NAME']:

$root = dirname($_SERVER['SCRIPT_NAME']);

Note that the script can be a symbolic link, in which case you need to call on readlink before you call dirname:

// Get the path of the script, eg. /usr/bin/myapp
$root = $_SERVER['SCRIPT_NAME'];
// Unwrap the links, eg. /usr/bin/myapp -> ~/myapp/myapp.phar
while (readlink($root)) {
    $root = readlink($root);
}
// Finally get the directory (~/myapp)
$root = dirname($root);

Use this to locate your plugins.

Find out if running from within a Phar

You can easilly find out if running from within a .phar archive by calling Phar::running().

if (Phar::running()) { inside_phar(); }

This doesn't make sense to use in phar plugins, as the main application can also be in a phar, in which case it will be true even for non-phar plugins.