2009-07-23 19 views
5

implementé la carga dinámica de los plugins de la siguiente manera:de descarga dinámica de clases en PHP

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

Cada plugin define una clase denominada PlginImpl, que trabaja muy bien. Pero debería ser posible llamar a otros complementos especificados dentro del valor de retorno de process(). Esto supondría el mismo método especificado anteriormente, pero falla con:

Fatal error: Cannot redeclare class PlginImpl in .. 

Tenga en cuenta que cada plugin es una clase, es decir .:

class PlginImpl extends Plugin implements PluginInterface 

Plugin ofrecer algunas funciones útiles mientras PluginInterface define decir process().

Supongo que el hecho de que todos los complementos se llamen PlginImpl causa el problema, de ahí mi pregunta: ¿hay alguna forma de descargar una clase (PlginImpl) después de cargarla con require_once? ¿O hay un enfoque completamente diferente que debería seguir?


EDITAR he intentado sin éxito las siguientes cosas:

  • desarmar $plgin después process()
  • llamando __destruct() - no funciona ni dentro ni processPlugin() dentro del método process

¡Muchas muchas gracias!

Respuesta

10

Como no puedes descargar una clase después de que la hayas cargado, la única opción que tienes es cambiar el nombre de cada complemento.

PluginX, PluginY, etc., pero no debería importar ya que puede obligarlos a usar la interfaz del complemento tal como lo mostró.

Para cargar un plugin específico, simplemente podría tener algo como solomongaby sugiere, pero en lugar de un nombre de archivo, se le pasa el nombre del plugin .. algo como esto:

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

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

lo podría hacer en tener la plgun-> método de proceso() llame a la Deconstructor http://ca.php.net/manual/en/language.oop5.decon.php

O

Usted podría tener el resultado de $ plgin-> process() almacenado en un var temp y luego unset ($ plgin)

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

Sin embargo creo que es probable que estés abordar el problema de una manera dura.

Quizás deberías tener un complemento de clase y luego tener Implement() ser un método.

+0

Intenté usar unset como se describe arriba, pero solo descarga la instancia de PlginImpl, pero la definición permanece en la memoria (los failes de la segunda ejecución). Deconstructor tampoco funciona. – MrG

0

me gustaría hacer una clase para manejar la carga de plug-in

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

y utilizarlo usted primero hacer una

pluginLoader::instance($db); 

y luego cargar un plugin

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

Muchas gracias, pero ¿no me encontraría exactamente con el mismo problema que antes debido al hecho de que todos los complementos se llaman "PlginImpl"? – MrG

+0

lo combinó con la solución anterior y usa los nombres de los complementos para el archivo de clase –

1

No estoy 100% seguro, pero no creo que puedas descargar una clase una vez que haya sido declarada.

Sin embargo, hay es una forma de lograr lo que estás tratando de hacer.

Nombre cada clase diferente y destruir una clase antes de crear la siguiente:

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

tendrá algunas clases adicionales definido dando vueltas, pero desarmado el plugin una vez cargado con suerte debe reducir al mínimo los problemas de memoria.

1

Sé que la pregunta se ha publicado hace muchos años, pero hoy me he caído en este problema, espero que este registro pueda ayudar a tener el mismo problema en el futuro.

Como se ha mencionado en muchas respuestas, PHP (al menos hasta 5.3) no permite descargar clases; lo que uno puede hacer es evitar conflictos entre nombres. Teniendo esto en cuenta, he escrito un código que carga cada complemento en un espacio de nombre único.

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

Los escritores de plugin deben ser conscientes de que están destinados clases referenciadas en relación con el contexto que crea por su anfitrión.

+0

PHP hasta 5.3 no te permite descargar una clase. Entonces, ¿cómo hacerlo en php 5.3+? – chiliNUT