2009-07-23 8 views
5

ich die dynamischen Laden von Plugins auf folgende Weise umgesetzt:Unload dynamische Klasse in PHP

function processPlugin($plgFile, $db) { 
    require_once($plgFile); 
    $plgin = new PlginImpl(); 
    $plgin->setDb($db); 
    $ret = $plgin->process(); 
    return $ret; 
} 

Jedes Plugin definiert eine Klasse PlginImpl benannt, der gut arbeitet. Es sollte jedoch möglich sein, weitere innerhalb des Rückgabewerts von process() angegebene Plugins aufzurufen. Das würde die gleiche Methode, die oben angegeben nennen, doch irgendwie:

Fatal error: Cannot redeclare class PlginImpl in .. 

Bitte beachten Sie, dass jedes Plugin eine Klasse ist, d.h .:

class PlginImpl extends Plugin implements PluginInterface 

Plugin bieten einige nützliche Funktionen während PluginInterface definiert das heißt process().

Ich nehme an, dass die Tatsache, dass alle Plugins PlginImpl genannt werden, das Problem verursacht, daher meine Frage: Gibt es eine Möglichkeit, eine Klasse (PlginImpl) nach dem Laden mit require_once zu entladen? Oder gibt es einen ganz anderen Ansatz, dem ich folgen sollte?


EDIT Ich habe versucht, ohne die folgenden Dinge Erfolg:

  • ungesetzt $plgin nach process()
  • __destruct() Aufruf - es ist nicht weder innerhalb processPlugin() funktioniert noch innerhalb der process Methode

Vielen, vielen Dank!

Antwort

10

zu laden Da Sie eine Klasse nicht entfernen können, nachdem Sie sie geladen haben, besteht die einzige Möglichkeit darin, jedes Plugin umzubenennen.

PluginX, PluginY, usw., aber es sollte nicht wichtig sein, da Sie sie nur zwingen können, die Plugin-Schnittstelle zu verwenden, wie Sie gezeigt haben.

ein bestimmtes Plugin zu laden, können Sie einfach so etwas wie solomongaby vermuten lässt, aber anstelle eines Dateinamens haben könnte, können Sie es den Namen des Plugins übergeben .. so etwas wie dieses:

function loadPlugin($pluginName) { 
    require_once $pluginName . '.php'; 

    $plugin = new $pluginName; 
    //do whatever with $plugin 
} 
0

Sie könnten Blick auf die plgun- mit> Prozess() -Methode aufrufen, die Deconstructor http://ca.php.net/manual/en/language.oop5.decon.php

Oder

Sie könnten das Ergebnis von plgin- $ haben> process() in einem temporären var gespeichert und dann unset ($ plgin)

function processPlugin($plgFile, $db) { 
    require_once($plgFile); 
    $plgin = new PlginImpl(); 
    $plgin->setDb($db); 
    $result = $plgin->process(); 
    unset($plgin); 
    return $result; 
} 

Allerdings glaube ich, dass Sie das Problem auf eine harte Art nähern.

Sie sollten vielleicht ein Klassen-Plugin haben und dann haben Implement() eine Methode sein.

+0

Ich habe versucht mit Unset wie oben beschrieben, aber es entlädt nur die Instanz von PlginImpl, aber die Definition bleibt im Speicher (der zweite Lauf fehlschlägt). Dekonstruktor funktioniert auch nicht. – MrG

0

würde ich eine Klasse macht den Plugin Laden

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; 
    } 
} 

zu handhaben und es zu benutzen, würden Sie zuerst tun, um ein

pluginLoader::instance($db); 

und dann ein Plugin

pluginLoader::instance()->load($plgFile); 
+0

Vielen Dank - aber würde ich nicht genau auf das gleiche Problem stoßen wie vorher, weil alle Plugins "PlginImpl" heißen? – MrG

+0

kombiniert es mit der obigen Lösung und verwenden Sie die Plugin-Namen für die Klassendatei –

1

Ich bin nicht 100% sicher, aber ich glaube nicht, dass Sie eine Klasse entladen können, sobald sie deklariert ist.

Allerdings ist ein Weg, um zu erreichen, was Sie versuchen zu tun.

Namen jeder Klasse anders und eine Klasse zerstören, bevor die nächste erstellen:

$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; 
} 

Sie werden einige zusätzliche Klassen definiert haben rumhängen, aber unsetting das Plugin einmal geladen sollte hoffentlich Speicherprobleme minimieren.

4

Eine andere Option, obwohl ich es nicht empfehle, ist runkit_import zu verwenden.

+1

Wusste nicht über diese. Cool :) – AntonioCS

1

Ich weiß, dass die Frage vor vielen Jahren gepostet wurde, aber ich habe heute zu diesem Thema abgestürzt, ich hoffe, dass dieses Protokoll helfen könnte, wie das gleiche Problem in Zukunft haben wird.

Wie es in vielen Antworten erwähnt wurde, erlaubt PHP (mindestens bis 5.3) nicht, Klassen zu entladen; Was man tun kann, ist Konflikte zwischen Namen zu vermeiden. In Erinnerung daran habe ich einen Code geschrieben, der jedes Plugin in einen eindeutigen Namespace lädt.

Die Plugin-Writer müssen sich bewusst sein, dass referenzierte Klassen im Zusammenhang mit dem Kontext stehen, den der Host für seinen Kontext erstellt.

+0

PHP bis 5.3 erlaubt Ihnen nicht, eine Klasse zu entladen. Also, wie macht man das in PHP 5.3+? – chiliNUT