arborint wrote:I have a couple of thoughts. I think I mentioned awhile back about not liking the loadBaseObject() fuctionality. It is usual for the plugin to be passed any data it needs when the callback occurs -- often the calling object itself (i.e. $this). I think that simplfies things.
Regarding the interface it seems like there are three ways to go:
1. a single plugin that is passed which point/state from which it is being called
2. a single plugin with a method per plugin point
3. an individual plugin for each plugin point
I think usage determines which one to use.
Ah you're quite right about loadBaseObject() being a bit off-ish. In fact I was just think the same earlier but I wrote a little interface to make things more obvious all the same, it's still a bit whacky... passing the object to be used locally would avoid that "recursive object strcuture" and make the logic a little more readable perhaps.
Little did I know that I'm basically trying to go beyond OOP and work with AOP in PHP (which of course isn't an AOP language).
The thing with me is I've never written anything that's designed to be pluggable before so this is all new to me and I'm sort of exploring if you like
Your points:
1. It's clean but it doesn't really allow you to do very much with a single plugin - then again, that's probably a good thing - a plugin should probably do one specific task and that's it. How might you code this if it needs to run multiple times without user-interaction though?
2. This would (perhaps) solve an issue I was thinking regarding "clashes" with multiple plugins... it still feels a little restrictive though.
3. Same sort of thing as above but better factored.
I think I've gotten into the wrong frame of mind from the outset. JavaScript was on my mind, hence my consideration for event handlers.
OK, now sit down:
"Forgive me for I have sinned dear lord...."

I've posted on SitePoint
One guy posted this however which also realtes with my way of of thinking about Javascript events (it's hacky like my stuff too though - just a lot more lengthy).
Ezku on SitePoint wrote:Here's something experimental I threw together a year ago. Oh, how this makes me wish PHP had closures...
Code: Select all
/**
* Delegate interface. Describes a kind of refined callback.
*
* @author Ezku (dmnEe0@gmail.com)
* @since Sep 6, 2005
*/
interface IDelegate
{
/**
* Invoke Delegate
* @param array arguments, optional
*/
public function invoke($args = array());
}
/**
* Calls a method on an object upon invocation.
*
* @author Ezku (dmnEe0@gmail.com)
* @since Sep 6, 2005
*/
class Delegate implements IDelegate
{
private $subordinate = NULL;
private $method = NULL;
public function __construct($subordinate, $method)
{
$this->subordinate = $subordinate;
$this->method = $method;
}
public function invoke($args = array())
{
$this->subordinate = Handle::resolve($this->subordinate);
$callback = array(&$this->subordinate, $this->method);
return call_user_func_array($callback, $args);
}
}
Code: Select all
/**
* "A Handle represents an uninstantiated object that takes the place of a
* given object and can be swapped out for the object.
* Implements lazy loading for composing object heirarchies."
*
* @author Ezku (dmnEe0@gmail.com)
* @since Jul 12, 2005
* @see [url]http://wact.sourceforge.net/index.php/ResolveHandle[/url]
*/
class Handle
{
/**
* @var string class name
*/
protected $class = NULL;
/**
* @var array class constructor arguments
*/
protected $args = array();
/**
* @param string class name
* @param array class constructor arguments, optional
*/
public function __construct($class, $args = array())
{
$this->class = (string) $class;
$this->args = (array) $args;
}
/**
* Resolves a Handle; replaces a Handle instance with its identified class
* @param object Handle
* @return object
*/
static public function resolve($handle)
{
if ($handle instanceof self)
{
$handle = call_user_constructor_array($handle->getClass(), $handle->getArgs());
}
return $handle;
}
public function getClass() { return $this->class; }
public function getArgs() { return $this->args; }
}
Code: Select all
/**
* Simple Event: attach a Delegate and trigger.
* @author Ezku (dmnEe0@gmail.com)
* @since 1.10.2005
*/
class Event
{
private $listener = NULL;
/**
* @param object IDelegate
* @return boolean overridden
*/
public function attach(IDelegate $listener)
{
$overridden = isset($this->listener);
$this->listener = $listener;
return $overridden;
}
/**
* @param array invocation arguments
* @return mixed results
*/
public function trigger($args = array())
{
return $this->listener->invoke($args);
}
/**
* Get attached listener
* @return object IDelegate
*/
public function getAttached()
{
return $this->listener;
}
}
/**
* Multicast Event: attach multiple Delegates.
* @author Ezku (dmnEe0@gmail.com)
* @since 1.10.2005
*/
class MulticastEvent extends Event
{
private $listeners = array();
/**
* @param object IDelegate
*/
public function attach(IDelegate $delegate)
{
$this->listeners[] = $delegate;
}
/**
* @param array invocation arguments
* @return array results
*/
public function trigger($args = array())
{
$return = array();
foreach($this->listeners as $listener)
{
$return[] = $listener->invoke($args);
}
return $return;
}
/**
* Get attached listeners
* @return array IDelegate
*/
public function getAttached()
{
return $this->listeners;
}
}
Code: Select all
/**
* Handle groups of events
* @author Ezku (dmnEe0@gmail.com)
* @since 26.9.2005
*/
class EventHandler
{
private $args = array();
private $events = array();
/**
* EventHandler consturctor
* @param mixed default invocation argument
* ...
*/
public function __construct()
{
$this->args = func_get_args();
}
/**
* Attach a listener to an event
* @param string event name
* @param object IDelegate
*/
public function attach($event, IDelegate $listener)
{
if(empty($this->events[$event]))
{
$this->events[$event] = $this->getEvent();
}
$this->events[$event]->attach($listener);
}
/**
* Trigger an event
* @param string event name
* @param array arguments, optional
*/
public function trigger($event, $args = array())
{
if(empty($args))
{
$args = $this->getArgs();
}
$return = NULL;
if(!empty($this->events[$event]))
{
$return = $this->events[$event]->trigger((array) $args);
}
return $return;
}
/**
* @return array default invocation arguments
*/
protected function getArgs()
{
return $this->args;
}
/**
* @return object a fresh Event
*/
protected function getEvent()
{
return new Event;
}
/**
* Shortuct for trigger()
*/
public function __call($event, $args)
{
return call_user_func_array(array($this, 'trigger'), array($event, $args));
}
/**
* Shortcut for attach()
*/
public function __set($event, $args)
{
return call_user_func_array(array($this, 'attach'), array($event, $args));
}
}
/**
* Extend EventHandler to use MulticastEvents
*
* @author Ezku (dmnEe0@gmail.com)
* @since 26.9.2005
*/
class MulticastEventHandler extends EventHandler
{
protected function getEvent()
{
return new MulticastEvent;
}
}
It's supposed to be used like this (a total nonsense example, bear with me):
Code: Select all
$events = new EventHandler;
$events->onload = new Delegate(new Handle('Controller'), 'execute');
$events->onload(Context::getInstance); // lazy-loads and creates a Controller instance, calls execute() with the arguments given
Here's a slightly more elaborate example, albeit on an older version of the code.
The whole idea is hacky to begin with, but aspect oriented programming in PHP seems doubly so to me. Just gives me a bad vibe.
