I implemented dynamic loading of plugins in the following way:
function processPlugin( $plgFile, $db ) {
require_once( $plgFile );
$plgin = new PlginImpl();
$plgin->setDb($db);
$ret = $plgin->process();
return $ret;
}
Each plugin defines a class named PlginImpl
, which works fine. But it should be possible to call further plugins specified within within the return value of process()
. That would call the same method specified above, but fails with:
Fatal error: Cannot redeclare class PlginImpl in ..
Please note that each plugin is a class, i.e.:
class PlginImpl extends Plugin implements PluginInterface
Plugin
offer some useful functions while PluginInterface
defines i.e. process()
.
I assume that the fact that all plugins are named PlginImpl causes the problem, hence my question: is there a way to unload a class (PlginImpl
) after loading it with require_once
? Or is there an entirely different approach I should follow?
$plgin
after process()
__destruct()
- it doesn't work neither within processPlugin()
nor within the process
methodSince you can't unload a class after you've loaded it, the only option you have is to rename each plugin.
PluginX, PluginY, etc., but it shouldn't matter as you can just force them to use the plugin interface as you showed.
To load a specific plugin, you could simply have something like solomongaby suggests, but instead of a filename, you pass it the name of the plugin.. something like this:
function loadPlugin($pluginName) {
require_once $pluginName . '.php';
$plugin = new $pluginName;
//do whatever with $plugin
}
Another option, though I don't recommend it, is to use runkit_import.
I'm not 100% sure, but I don't believe you can unload a class once it's declared.
However, there is a way to accomplish what you're trying to do.
Name each class differently and destroy one class before creating the next:
$class1 = "foo";
$class2 = "bar";
$pluginResult = processPlugin($class1);
// do stuff
$pluginResult = processPlugin($class2);
function processPlugin($pluginName, $db) {
require_once( $pluginName . ".inc" ); //or whatever scheme you want to use.
$plgin = new $plugin;
$plgin->setDb($db);
$ret = $plgin->process();
unset($plgin);
return $ret;
}
You'll have some extra defined classes hanging around, but unsetting the plugin once loaded should hopefully minimize memory issues.
I know the question has been posted many years ago, but I've crashed to this issue today, I hope that this log could help how'll have the same problem in future.
As it'has been mentioned in many responses, PHP (at least until 5.3) doesn't allow to unload classes; what one can do is to avoid conflicts between names. Keeping this in mind I've written a code that load each plugin in a unique namespace.
$uniqueContext = 'Context_'.rand();
$content = file_get_contents($actionScript);
if (strstr($content, '<?php')) {
$content = str_replace('<?php', "<?php namespace $uniqueContext;", $content);
} else {
if (strstr($content, '<?')) {
$content = str_replace('<?', "<?php namespace $uniqueContext;", $content);
} else {
$content = "namespace $uniqueContext;".$content;
}
}
$tmp=array_search('uri', @array_flip(stream_get_meta_data($GLOBALS[mt_rand()]=tmpfile())));
file_put_contents($tmp, $content);
require_once($tmp);
The plugin writers must be aware that referenced classes are meant related to the context that host creates for its.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With