php-makephar/doc/PHAR-PLUGINS.md

99 lines
2.5 KiB
Markdown

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.