我通过以下方式实现了动态加载插件:
function processPlugin( $plgFile, $db ) {
require_once( $plgFile );
$plgin = new PlginImpl();
$plgin->setDb($db);
$ret = $plgin->process();
return $ret;
}
每个插件定义一个名为PlginImpl
的类,它可以正常工作。但是应该可以在process()
的返回值内调用指定的其他插件。这将调用上面指定的相同方法,但失败的是:
Fatal error: Cannot redeclare class PlginImpl in ..
请注意,每个插件都是一个类,即:
class PlginImpl extends Plugin implements PluginInterface
Plugin
提供了一些有用的功能,PluginInterface
定义了process()
。
我认为所有插件都名为PlginImpl的事实会导致问题,因此我的问题是:有没有办法在用PlginImpl
加载类后卸载一个类(require_once
)?或者我应该遵循一种完全不同的方法吗?
<小时/> 编辑 我试过没有成功完成以下事情:
$plgin
process()
__destruct()
- 它既不在processPlugin()
内也不在process
方法很多,非常感谢!
答案 0 :(得分:11)
由于您在加载类后无法卸载它,因此您唯一的选择就是重命名每个插件。
PluginX,PluginY等,但它应该无关紧要,因为你可以强制它们使用你所显示的插件界面。
要加载一个特定的插件,你可以简单地拥有像solomongaby建议的东西,但不是文件名,而是传递插件的名称..这样的东西:
function loadPlugin($pluginName) {
require_once $pluginName . '.php';
$plugin = new $pluginName;
//do whatever with $plugin
}
答案 1 :(得分:4)
另一种选择,虽然我不推荐,但是使用runkit_import。
答案 2 :(得分:1)
我不是百分百肯定,但我不相信你一旦声明就可以卸载一个类。
然而,是一种完成你想要做的事情的方法。
以不同方式命名每个类并在创建下一个类之前销毁一个类:
$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;
}
你会有一些额外定义的类,但是一旦加载就取消设置插件应该有希望最小化内存问题。
答案 3 :(得分:1)
我知道这个问题已经在很多年前发布了,但我今天已经遇到了这个问题,我希望这个日志有助于将来遇到同样的问题。
正如许多回复中提到的那样,PHP(至少在5.3之前)不允许卸载类;可以做的是避免名称之间的冲突。牢记这一点,我编写了一个代码,将每个插件加载到一个唯一的命名空间中。
$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);
插件编写者必须知道,引用的类与主机为其创建的上下文相关。
答案 4 :(得分:0)
您可能会考虑让plgun-&gt; process()方法调用解构函数http://ca.php.net/manual/en/language.oop5.decon.php
或者
您可以将$ plgin-&gt; process()的结果存储在temp var中然后取消设置($ plgin)
function processPlugin( $plgFile, $db ) {
require_once( $plgFile );
$plgin = new PlginImpl();
$plgin->setDb($db);
$result = $plgin->process();
unset($plgin);
return $result;
}
但是我认为你可能正在艰难地解决这个问题。
你应该有一个类插件,然后将Implement()作为一种方法。
答案 5 :(得分:0)
我会创建一个类来处理插件加载
class pluginLoader {
protected $_plugins = array();
protected $_db;
public function setDB($db) {
$this->_db = $db;
}
public function load($plgFile) {
if (!isset($this->_plugins[$plgFile])) {
require_once( $plgFile );
$plgin = new $plgFile();
$plgin->setDb($this->_db);
$this->_plugins[$plgFile] = $plgin;
}
$this->_plugins[$plgFile]->process();
}
public static function instance($db) {
static $instance;
if (!$instance instanceof self) {
$instance = new self($db);
}
return $instance;
}
}
并且要使用它,你首先要做
pluginLoader::instance($db);
然后加载插件
pluginLoader::instance()->load($plgFile);