在PHP中卸载动态类

时间:2009-07-23 14:41:33

标签: php

我通过以下方式实现了动态加载插件:

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方法

很多,非常感谢!

6 个答案:

答案 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);