2.5 KiB
2.5 KiB
Plugins in Phar Archives
This is a short guide on how to create single-file portable plugins using MakePhar.
The workflow
- Your application should export functions that can be called by the plugin
on load, such as
myapp_plugin_register
in the example below. - Locate the .phar plugins to load, and
@include
them one at a time. - 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.