Best Way to Allow Plugins for a PHP Application

Best way to allow plugins for a PHP application

You could use an Observer pattern. A simple functional way to accomplish this:

<?php

/** Plugin system **/

$listeners = array();

/* Create an entry point for plugins */
function hook() {
global $listeners;

$num_args = func_num_args();
$args = func_get_args();

if($num_args < 2)
trigger_error("Insufficient arguments", E_USER_ERROR);

// Hook name should always be first argument
$hook_name = array_shift($args);

if(!isset($listeners[$hook_name]))
return; // No plugins have registered this hook

foreach($listeners[$hook_name] as $func) {
$args = $func($args);
}
return $args;
}

/* Attach a function to a hook */
function add_listener($hook, $function_name) {
global $listeners;
$listeners[$hook][] = $function_name;
}

/////////////////////////

/** Sample Plugin **/
add_listener('a_b', 'my_plugin_func1');
add_listener('str', 'my_plugin_func2');

function my_plugin_func1($args) {
return array(4, 5);
}

function my_plugin_func2($args) {
return str_replace('sample', 'CRAZY', $args[0]);
}

/////////////////////////

/** Sample Application **/

$a = 1;
$b = 2;

list($a, $b) = hook('a_b', $a, $b);

$str = "This is my sample application\n";
$str .= "$a + $b = ".($a+$b)."\n";
$str .= "$a * $b = ".($a*$b)."\n";

$str = hook('str', $str);
echo $str;
?>

Output:

This is my CRAZY application
4 + 5 = 9
4 * 5 = 20

Notes:

For this example source code, you must declare all your plugins before the actual source code that you want to be extendable. I've included an example of how to handle single or multiple values being passed to the plugin. The hardest part of this is writing the actual documentation which lists what arguments get passed to each hook.

This is just one method of accomplishing a plugin system in PHP. There are better alternatives, I suggest you check out the WordPress Documentation for more information.

Is there any php framework to build a web app with plugins feature?

Frameworks don't handle things like that. You need to code it in plug-in way.

Following scenario will allow you to code in plug-in fashion:

Lets say we have directory called plugins in the root of the site and a table in the database called plugins with following structure (id, name, enabled, path)

Now you need to create an interface for your plug-ins. This way all plug-ins will have same basic structure.

/**
* FILE: /plugins/PluginInterface.php
*
* Sample Interface
*/
interface iPlugin{

/**
* Tests if plug-in can be executed
*/
function test();

/**
* Prepared plug-in for execution
*/
function prepare();

/**
* Executes plug-in logic and returns count of somethings
*/
function execute();
}

/**
* FILE: /plugins/PluginExample.php
*
* Sample Plug-in
*/
class PluginExample implements iPlugin{

public function execute() {

}

public function prepare() {

}

public function test() {

}
}

Now you need to insert a record for the PluginExample in the database.

INSERT INTO plugins (id, name, enabled, path) VALUES (1, 'Example', 1, 'PluginExample.php')

And lastly you need somekind of controller that loads all the enabled plugins from the database (get's path) and the creates objects and executes them. Like so

function loadAndExecutePlugins() {
$query = "select * from plugins where enabled = 1";
$plugins = 'array of objects from query 1';

if ($plugins) {
foreach ($plugins as $plugin) {
//
$class = $plug->path;
include_once "/plugins/$class";

// Class is using interface, so you know what methods to call
$plug = new $class();
if ($plug->test()) {
$plug->execute();
}
}
}
}

How to make plugin-like web application with PHP?

There are multiple issues to consider. As you noted a plugin system depends on registering extensions with the application, and the extension itselfs need a way to hook into the main application.

For all its faults, Wordpress has a quite workable approach to this. It uses "hooks" for interfacing to plugins. That's basically a callback-system which more or less can amount to "event-driven" too. Fundamentally the main application does something like:

foreach ($callback["need_to_render_sidebar"] as $fn) {
$fn();
}

But you can make it more flexible with passing extra parameters, returning data, and more importantly: using objects rather than procedural callbacks for more complex features. (I'd avise to mix and match. There's not one approach that suits all applications or extensions.)

Likewise a plugin system often enables the extensions itself to call back the main application, feed data into it, or modify settings.

The second part you need to consider for a plugin system is how you make it manageable. There basically each WebCMS/DMS has its own approach. Many use zip files to be manually extracted, or module directories. For starters a WP-like approach of meta-data augmented script files is the most suitable. I made a similar system which can be used independently of WP, though it's pretty rough: http://milki.include-once.org/genericplugins/ (the nice part is actually the manageability of settings.)

Design pattern for implementing plugins in PHP applications

There is no consensus as in the Silver Bullet sense. For established patterns, you have multiple options like

  • Subject/Observer,
  • Signal Slot,
  • Event Dispatcher or
  • Pipes and Filters

to name a few.

Which you use is up to you, but you should make sure your system architecture supports the modularity. Have a look at these slides for some ideas

  • http://qafoo.com/talks/11_06_ipc_spring_modular_application_architecture.pdf

how to write an app to allow for plugins?

There's plenty of ways for it, but simple:

Scan for folder :

string[] files = System.IO.Directory.GetFiles("yourpath", "*.dll");

Then load assembly (for each file above)

Assembly.Load or Assembly.LoadFrom

From Assembly to enumerate types:

Type[] types = assembly.GetTypes();

Check if type implements your interface

Type t;
YourInterface.IsAssignableFrom(t);

Then to instanciate:

object o = Activator.CreateInstance(t);
YourInterface iface = (YourInterface)o;

That's about it, exception handling and other bits omitted of course

Some DI packages can do lot of that work for you, depending on your use case they can be very useful or just overkill.

what is the best way to create a self-installing, all-included package for distributing a Symfony application?

Use virtual machine. There you create your own environment, specific to your package. So you can control things. It is pretty complex task to create php installer though: lots of nuances with server software on different environments.

Also - it is easier to maintain and to deploy the virtual machine.



Related Topics



Leave a reply



Submit