Class PEAR_Delegator

Description

Base class for objects that allow delegation.

It is first necessary to discuss the role of delegates in PEAR. With the advent of PHP 5, a whole host of new programming techniques were introduced. Among them were class interfaces. These interfaces provide much of the benefits of multiple inheritance (with regard to methods) without adulterating the inheritance hierarchy. That is, an object can inherit from a parent class as usual, but still possess methods that qualify it as a member of another group of objects, related by certain behavior but still exclusively separate in the hierarchy. The interfaces, however, only define the protocol to which each adopting class must adhere, but they do not define the implementation. This is very useful in many instances, but for some purposes, the implementation remains viritually the same for all adopting parties. This is where delegation enters.

A delegate is a class that defines methods which are intended to be called by an adopting object as if they were members of that object. For instance,

  1. class Foo extends PEAR_Delegator
  2. {
  3. public function _construct()
  4. {
  5. parent::_construct();
  6. }
  7.  
  8. public function _destruct()
  9. {
  10. parent::_destruct();
  11. }
  12. }
  13.  
  14. $foo = new Foo();
  15. $foo->bar() //This results in a runtime error,
  16. //Foo has no such method.
  17.  
  18. //Now define a delegate. Note that the constructor and destructor
  19. //are unnecessary, as this delegate will be added statically.
  20.  
  21.  
  22. class Delegate
  23. {
  24. public function _construct()
  25. {
  26. parent::_construct();
  27. }
  28.  
  29. public function _destruct()
  30. {
  31. parent::_destruct();
  32. }
  33.  
  34. public function bar()
  35. {
  36. echo "bar";
  37. }
  38. }
  39.  
  40. foo->addDelegate(Delegate); //add the delegate.
  41. foo->bar(); //This will be called as if it
As many delegates as necessary can be added to an object, and they can be either class objects or instance objects. Class objects have their methods called statically.

You may wonder about the performance impact of this model. In actuality, there should be little extra overhead after the first call to a delegated method. This is due to a caching scheme: When methods are called upon a delegator, the delegator checks another associated array that contains method names as keys and the proper delegates as values. If the key (method name) is cached in this manner, then the method is immediatly invoked on the proper delegate. If it does not exist, then each delegate is searched until one that can respond is found and this relationship is cached, otherwise, a fatal error is produced. Thus no matter how many delegates a class has, all calls after the first should only have a small latency.

To call the method, PEAR_Delegator implements the __call() method. When it finds the correct delegate, it calls the method, transparently inserting a reference to the owning object ($this) as the first argument, so that the delegate can act on its owner as if it is itself. Thus, delegated methods must be defined as follows:

  1. accesslevel function functionName($owner, ...);
Note, however, that the user of the method need only consider those parameters that follow the first parameter.

One of the benefits of this scheme is the ability to have delegate hierarchies. That is, a delegator could have a delegate that is a delegator, and the PEAR_Delegator class recognizes this by viewing such delegates as subdelegates, treating such subdelegates as subclasses would be treated. This allows for such capabilities as pseudo-overriding:

  1. //In our Foo class we could define a bar() method as follows:
  2. public function bar()
  3. {
  4. $args = func_get_args();
  5. $this->forwardMethod("bar", $args);
  6.  
  7. echo "foobar";
  8. }
Now, the delegate's implementation would be called as well. This of course means that you can also completely override the delegate method, and not even call it.

In truth, this mode of delegation is unorthodox. The traditional model of delegation is that an object delegates selected methods, calling its own version unless one delegate is present. This feature is, in fact, a subset of the scheme presented here. In otherwords, you can achieve the same effect by limiting the forwarding mechanism:

  1. //In our Foo class, we could define a bar() method as follows:
  2. public function bar()
  3. {
  4. if ($this->hasDelegate()) {
  5. $args = func_get_args();
  6. return $this->forwardMethod("bar", $args);
  7. }
  8.  
  9. echo "foobar";
  10. }
  11.  
  12. //Now, if you call:
  13. $foo->bar();
  14. //you get the functionality provided by the class,
  15. //but if you set the delegate:
  16. $foo->setDelegate(Delegate); //or instantiate the
  17. //delegate and set the object.
  18. //You can use its functionality instead.

Some might also worry about the flexibility of errors. This is not a trouble at all. In fact, the error output of this class is more direct in many cases than PHP's own error output. It will give you the file and line of the error in user code and its messages are modeled after those of PHP.

Terminology:

 * owner: a delegator.
 * subdelegate: A delegator that is a delegate.
 * native delegate: A delegate that is an immediate delegate, not a delegate
   of a delegate.
 * static (class) delegate: A delegate that is simply the class.
 * dynamic (object) delegate: A delegate that is an instantiated class.

Located in /Delegator.php (line 197)


	
			
Variable Summary
Method Summary
PEAR_Delegator __construct ()
void __destruct ()
void addDelegate (mixed $delegate, mixed $delegate,...)
void addExtensions ()
void cacheMethod (string $method)
array filterMethodMapWithDelegate (object $filterDelegate)
void forwardMethod (string $method, string $args)
array &getAllDelegates ()
array getDelegate (class $classname1)
array getDelegateForMethod (mixed $method1, string $method1,...)
bool hasDelegate ([mixed $specifier = null])
bool is_a (mixed $specifier, class $classname)
bool is_aExact (mixed $specifier, class $classname)
bool method_exists (mixed $specifier, mixed $method, class $classname)
bool method_existsExact (mixed $specifier, mixed $method, class $classname)
void removeDelegate (mixed $specifier, mixed $specifier,...)
bool respondsToMethod (string $method)
void setDelegate (mixed $delegate)
void setForwardingMethod (string $method)
mixed __call (string $method, string $args)
Variables
array $_delegates = array() (line 204)

An associative array with delegate classnames as keys and objects as values.

  • access: public
string $_forwardingMethod (line 217)

This is checked by the forwarding mechanism to find which object should be considered the calling object.

  • access: public
array $_method_map = array() (line 210)

An associative array with delegated methods as keys and delegate objects as values.

  • access: public
Methods
Constructor __construct (line 223)

Constructs a delegator.

  • access: public
PEAR_Delegator __construct ()
Destructor __destruct (line 233)

Destroys a delegator.

When a delegator is destroyed, it automatically removes all of the delegates, so it is unnessary for user code to do so.

  • access: public
void __destruct ()
addDelegate (line 264)

Adds delegates to the calling object.

This method takes a list of classnames or objects. If an argument is a classname, then the method determines if it is defined. If it is, the class is added as a static delegate, otherwise a fatal error is raised. If it is an object, it is stored as a delegate; thus, there are two types of delegates: static and dynamic delegates.

void addDelegate (mixed $delegate, mixed $delegate,...)
  • mixed $delegate,...: This specifies either a classname or an object.
addExtensions (line 243)

Add extensions to this class.

This adds the PEAR_Delegator_Extensions delegate.

  • access: public
void addExtensions ()
cacheMethod (line 707)

Stores the relationship between method names and delegates.

Takes a method name, searches for the delegate that can handle it, and stores the relationship in the _method_map array. This method is called when the __call() method reveives an unrecognized method. This caching of methods speeds up delegation. If the method cannot be handled by any of the adopted delegates, then an Exception is thrown.

Note: This caches the first responding delegate.

This is an internal method and should not be invoked.

void cacheMethod (string $method)
  • string $method: The method name that is to be cached. This must be a lowercase string.
filterMethodMapWithDelegate (line 515)

Removes the unwanted entries from _method_map.

This method cleans the _method_map array when a call to removeDelegate*() is made.

  • return: The method map without the $filterdelegate
  • access: public
array filterMethodMapWithDelegate (object $filterDelegate)
  • object $filterDelegate: Specifies the delegate instance, whose information is is to be removed.
forwardMethod (line 748)

This can be used by delegators for pseudo-method-overriding a method.

This is the public interface to the __call() method, and it allows for a method to be forwarded to the delegation system, so that pseudo-method-overriding can occur.

void forwardMethod (string $method, string $args)
  • string $method: See the PHP documentation.
  • string $args: See the PHP documentation
getAllDelegates (line 325)

Gets the associated array of delegate classes => delegates.

Note: Cloning may not work after this.

array &getAllDelegates ()
getDelegate (line 366)

Gets the delegate objects that are instances of the specified class.

This method returns instances of the specified classname as well as child instances of the specified classnames, including subdelegates, which are native to the caller. That is, if one of the delegates is a delegator and it contains a delegate of the specified type, it will be returned regardless of its own class type.

array getDelegate (class $classname1)
  • class $classname1: This specifies a delegate classname. Any number of arguments after this is acceptable.
getDelegateForMethod (line 422)

Gets the native delegate objects that respond to a certain method.

The method returns delegates native to the calling delegator, which can respond to the method in question, whether it be defined in the native delegate or in a delegate deeper in the hierarchy.

array getDelegateForMethod (mixed $method1, string $method1,...)
  • string $method1,...: This specifies the method for whose responder is searched.
hasDelegate (line 457)

Determines whether or not the calling object adopts a particular delegate.

This returns the availability of a delegate, including subdelegates.

bool hasDelegate ([mixed $specifier = null])
  • mixed $specifier: This specifies a delegate classname or object. If $delegate is a string, then it adheres to the tests of getDelegate(). If $delegate is an object, the _delegates array is searched for the object. If $specifier is null, then this returns whether or not the caller has any delegates.
is_a (line 603)

Determines if a class or instance object is of the given type.

This method is an extension of the is_aExact() method. It also handles subdelegates, so it returns true if a delegator is passed in and has a delegate of type $classname, whether or not the delegator is of type $classname.

bool is_a (mixed $specifier, class $classname)
  • mixed $specifier: Specifies the delegate with either a class or instantiated object.
  • class $classname: The classname type to check against.
is_aExact (line 575)

Determines if a class or instance object is of the given type.

This method is analogous to the is_a() method of PHP. However, it handles classes too.

bool is_aExact (mixed $specifier, class $classname)
  • mixed $specifier: Specifies the delegate with either a class or instantiated object.
  • class $classname: The classname type to check against.
method_exists (line 655)

Determines if a class or instance object responds to a method.

This method is an extension of the method_existsExact() method. It also handles subdelegates, so it returns true if a delegator is passed in and has a delegate that can implement $method, whether or not the delegator can implement the $method.

bool method_exists (mixed $specifier, mixed $method, class $classname)
  • mixed $specifier: Specifies the delegate with either a class or instantiated object.
  • class $classname: The method to look for.
method_existsExact (line 628)

Determines if a class or instance object responds to a method.

This method is analogous to the method_exists() method of PHP. However, it handles classes too.

bool method_existsExact (mixed $specifier, mixed $method, class $classname)
  • mixed $specifier: Specifies the delegate with either a class or instantiated object.
  • class $classname: The method to look for.
removeAllDelegates (line 496)

Removes all delegates.

This completely cleans the calling object of any delegates.

void removeAllDelegates ()
removeDelegate (line 549)

Removes the specified delegate.

Takes a list of delegate classnames and delegate objects and removes them from the calling object.

void removeDelegate (mixed $specifier, mixed $specifier,...)
  • mixed $specifier,...: Specifies the delegate, whose information is is to be removed. If it is a string, then it adheres to the tests of getDelegate(). If it is an object, then it searches the for that delegate to remove.
respondsToMethod (line 684)

Finds whether or not the object or one of its delegates implements a method

Finds whether or not the calling object can perform the given method name. The calling object can perform the given method if it or one of its delegates can do so. This means that it also searches delegates that are themselves delegators.

bool respondsToMethod (string $method)
  • string $method: The method name that is to be searched for availability.
setDelegate (line 308)

Sets the delegator's one delegate.

This method takes a classname or an object and makes it the only delegate. In actuality, it removes all of the delegates and then adds the specified delegate. This is useful for using the delegation method for the traditional delegate model.

void setDelegate (mixed $delegate)
  • mixed $delegate: This specifies either a classname or an object.
setForwardingMethod (line 732)

This informs a delegator that is a delegate not to pass itself.

This informs a delegator that is a delegate not to pass itself as the calling object if it needs to forward a method to a delegate. Thus, a chain of responders is established with the initial caller as the caller.

This is an internal method and should not be invoked.

  • access: protected
void setForwardingMethod (string $method)
  • string $method: The method that is being forwarded. This must be a lowercase string.
__call (line 771)

Processes unrecognized method signatures.

This checks the _method_map array for a cached relationship between the method and any delegate. If one exists, the method is immediately called and the result returned. If it does not, then it calls the cacheMethod() method to find and cache the method, after which is calls the unrecognized method on the proper delegate or kills the PHP with an error.

This is an internal method and should not be invoked.

mixed __call (string $method, string $args)
  • string $method: See the PHP documentation.
  • string $args: See the PHP documentation.

Documentation generated on Fri, 25 Feb 2005 17:29:12 -0500 by phpDocumentor 1.3.0RC3