Re: Re: Flexible application plugin architecture, is this possible?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Colin,

	I guess I'm on the right track then, I ended up doing something
similar to your suggestion, instead of using a Factory method in each
class I created a global function that can be used as the instantiator
instead. 

The only advantage I see to doing it this way is that it will work for
classes that don't extend my base "Factory" class, so it requires the
least amount of existing code change as possible. 

//The basis for the plugin system, instantiate all classes through this, allowing the class to be overloaded on the fly by a class in the plugin directory.
function MyInstantiator( $class_name ) { //Unlimited arguments are supported.
    global $config_vars;

    //Check if the plugin system is enabled in the config.
    if ( isset($config_vars['other']['enable_plugins']) AND $config_vars['other']['enable_plugins'] == 1 ) {
        $plugin_class_name = $class_name.'Plugin';

		if ( class_exists( $plugin_class_name, FALSE ) == FALSE ) {
			//Class file needs to be loaded.
			$plugin_directory = 'plugins';
			$plugin_class_file_name = $plugin_directory . DIRECTORY_SEPARATOR . $class_name .'.plugin.php';
			if ( file_exists( $plugin_class_file_name ) ) {
				@include_once( $plugin_class_file_name );
				$class_name = $plugin_class_name;
			}
		} else {
			//Class file is already loaded.
			$class_name = $plugin_class_name;
		}
    }

    if ( func_num_args() > 1 ) {
        $params = func_get_args();
        array_shift( $params ); //Eliminate the class name argument.

		$reflection_class = new ReflectionClass($class_name);
		return $reflection_class->newInstanceArgs($params);
    } else {
		return new $class_name();
    }
}

$main_class = MyInstantiator('MyClass', 'arg1', 'arg2', 'arg3');
$main_class->doSomething( 'foo' );



On Tue, 04 Jan 2011 11:43:13 +0000
Colin Guthrie <gmane@xxxxxxxxxxxxxx> wrote:

> 'Twas brillig, and Mike at 03/01/11 23:37 did gyre and gimble:
> > I'm trying to design a powerful plugin system that doesn't require any
> > (or extremely little) modification to my existing large code base. Hook
> > based systems unfortunately don't seem to meet this requirement. 
> > 
> > Is something like this possible in PHP?
> > 
> > //Magic function I made up, similar to __call(), 
> > //only it replaces "new $class" with its own return value.
> > function __instantiate( $class, $args ) {
> >     $plugin_class = $class.'Plugin';
> > 
> >     if ( file_exists( 'plugins/'.$plugin_class.'.php' ) {
> >         $obj = new $plugin_class($args);
> >         return $obj;
> >     } else {
> >         return new $class($args);
> >     }
> > }
> 
> I'd implement the above as a static "factory" method of your primary
> class: e.g.
> 
> > class MainClass {
> 
>     public static function factory($args = null) {
>         $plugin_class = __CLASS__ . 'Plugin';
>         // Assume autoloading....
>         if (class_exists($plugin_class))
>           return new $plugin_class($args);
>         return new self($args);
>     }
> 
>     protected function __construct($args) {
>     }
> 
> >     function doSomething( $args ) {
> >         echo "MainClass doSomething() called...\n";
> >     }
> > }
> > 
> > class MainClassPlugin extends MainClass {
> >     function doSomething( $args ) {
> >         echo "MainClassPlugin doSomething() called...\n";
> > 
> >         //Modify arguments if necessary
> >         echo "MainClassPlugin modifying arguments...\n";
> > 
> >         $retval = parent::doSomething( $args );
> > 
> >         //Modify function output, or anything else required
> >         echo "MainClassPlugin post filter...\n";
> > 
> >         return $retval;
> >     }
> > }
> > 
> > $main_class = new MainClass();
> 
> And replace this line with:
> $main_class = MainClass::factory();
> 
> 
> > $main_class->doSomething( 'foo' );
> 
> Which, when run, does indeed produce your desired results.
> 
> > Results:
> > MainClassPlugin doSomething() called...
> > MainClassPlugin modifying arguments...
> > MainClass doSomething() called...
> > MainClassPlugin post filter...
> > 
> > I realize PHP doesn't have this magical "__instantiate" function, but
> > does it have any similar mechanism that would work to automatically
> > load alternate classes, or have a class dynamically overload
> > itself during runtime?
> 
> Well difference techniques require different approaches, but certainly a
> factory approach is likely the correct design solution here to get the
> desired results.
> 
> 
> Full code for convenience:
> 
> <?php
> 
> class MainClass {
>     public static function factory($args = null) {
>         $plugin_class = __CLASS__ . 'Plugin';
>         // Assume autoloading....
>         if (class_exists($plugin_class))
>           return new $plugin_class($args);
>         return new self($args);
>     }
> 
>     protected function __construct($args) {
>     }
> 
>     function doSomething( $args ) {
>         echo "MainClass doSomething() called...\n";
>     }
> }
> 
> class MainClassPlugin extends MainClass {
>     function doSomething( $args ) {
>         echo "MainClassPlugin doSomething() called...\n";
> 
>         //Modify arguments if necessary
>         echo "MainClassPlugin modifying arguments...\n";
> 
>         $retval = parent::doSomething( $args );
> 
>         //Modify function output, or anything else required
>         echo "MainClassPlugin post filter...\n";
> 
>         return $retval;
>     }
> }
> 
> $main_class = MainClass::factory('wibble');
> $main_class->doSomething( 'foo' );
> 
> 


-- 
Mike

-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php



[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux