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 the 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 function1($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. {
  6. $args = func_get_args();
  7. return $this->forwardMethod("bar", $args);
  8. }
  9.  
  10. echo "foobar";
  11. }
  12.  
  13. //Now, if you call:
  14. $foo->bar();
  15. //you get the functionality provided by the class,
  16. //but if you set the delegate:
  17. $foo->setDelegate(Delegate); //or instantiate the
  18. //delegate and set the object.
  19. //You can use its functionality instead.

Some might also worry about the flexibility of errors. This is not 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 190)

PEAR
   |
   --PEAR_Delegator
Variable Summary
Method Summary
PEAR_Delegator __construct ()
void __destruct ()
void addDelegate (mixed $delegate, mixed $delegate,...)
void cacheMethod (string $method, [mixed $delegate = null])
array filterMethodMapWithDelegate (object $filterDelegate)
void forwardMethod (string $method, string $args)
array getDelegate (class $classname1)
array getDelegateExact (class $classname1)
array getDelegateForMethod (mixed $method1, string $method1,...)
array getDelegateForMethodFirst (mixed $method, string $method,...)
array getDelegateForMethodRecursive (mixed $method1, string $method1,...)
array getDelegateForMethodRecursiveExact (mixed $method1, string $method1,...)
array getDelegateRecursive (class $classname1)
array getDelegateRecursiveExact (class $classname1)
array &getDelegates ()
bool hasDelegate ([mixed $specifier = null])
bool hasDelegateExact ([class $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,...)
void removeDelegateRecursiveExact (mixed $specifier, mixed $specifier,...)
bool respondsToMethod (string $method)
void setDelegate (mixed $delegate)
void setForwardingMethod (string $method)
bool uncacheMathod (string $method)
mixed __call (string $method, string $args)
Variables
array $_delegates = array() (line 197)

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

  • access: protected
string $_forwardingMethod (line 210)

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

  • access: protected
array $_method_map = array() (line 203)

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

  • access: protected
Methods
Constructor __construct (line 216)

Constructs a delegator.

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

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 242)

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.

  • access: public
void addDelegate (mixed $delegate, mixed $delegate,...)
  • mixed $delegate,...: This specifies either a classname or an object.
cacheMethod (line 1229)

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.

void cacheMethod (string $method, [mixed $delegate = null])
  • string $method: The method name that is to be cached. This must be a lowercase string.
  • mixed $delegate: (Optional) Must be either an object or a classname.
filterMethodMapWithDelegate (line 966)

Removes the unwanted entries from _method_map.

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

array filterMethodMapWithDelegate (object $filterDelegate)
  • object $filterDelegate: Specifies the delegate instance, whose information is is to be removed.
forwardMethod (line 1291)

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

Tnis 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
getDelegate (line 346)

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.

  • return:
    The result is an
     associative array of the form:
     Array
     (
         [classname1] = Array
                        (
                            delegate11
                            delegate12
                            ...
                        )
         [classnamei] = Array
                        (
                            delegate1i
                            delegate1i
                            ...
                        )
         ...
     )
     Note: If a single classname is passed, a traditional array with numbered
     elements is returned.
  • access: public
  • see: PEAR_Delegator::getDelegateExact()
array getDelegate (class $classname1)
  • class $classname1: This specifies a delegate classname. Any number of arguments after this is acceptable.
getDelegateExact (line 408)

Gets the delegate object that is an instance of the specified class.

This method returns classes of the specified type. This does not return subdelegates. That is, it uses only the actual class structures.

  • return:
     The result is an
     associative array of the form:
     Array
     (
         [classname1] = Array
                        (
                            delegate11
                            delegate12
                            ...
                        )
         [classnamei] = Array
                        (
                            delegate1i
                            delegate1i
                            ...
                        )
         ...
     )
     Note: If a single classname is passed, a traditional array with numbered
     elements is returned.
  • access: public
  • see: PEAR_Delegator::getDelegate()
array getDelegateExact (class $classname1)
  • class $classname1: This specifies a delegate classname. Any number of arguments after this is acceptable.
getDelegateForMethod (line 613)

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.
getDelegateForMethodFirst (line 664)

Gets the first native delegate objects that responds to a certain method.

The method returns the first delegate native to the calling delegator, which can respond to each method in question. Moreover, this method returns delegates that actually implement methods over those that inherit them from delegates. Since the forwarding mechanism uses this method to find the delegate, the first delegate that actually implements the given method takes precedent.

array getDelegateForMethodFirst (mixed $method, string $method,...)
  • string $method,...: This specifies the method for whose responder is searched.
getDelegateForMethodRecursive (line 751)

Gets the delegate objects that respond to a certain method.

This method returns delegates native to the calling delegator as well as delegates of delegate owning delegates (it's recursive). This method is provided, because it may be useful, but its use is discouraged, as objects should logically only have access to their native delegates.

array getDelegateForMethodRecursive (mixed $method1, string $method1,...)
  • string $method1,...: This specifies the method for whose responder is searched.
getDelegateForMethodRecursiveExact (line 822)

Gets the delegate object (native or otherwise) that implements the method in question.

This method returns the delegate in the delegate hierarchy which actually implements the method. This method is provided, because it may be useful, but its use is discouraged, as objects should logically only have access to their native delegates.

array getDelegateForMethodRecursiveExact (mixed $method1, string $method1,...)
  • string $method1,...: This specifies the method for whose implementor is searched.
getDelegateRecursive (line 468)

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 classname, including subdelegates, which are anywhere in the delegate hierarchy. This method is provided, because it may be useful, but its use is discouraged, as objects should logically only have access to their native delegates.

  • return:
     The result is an
     associative array of the form:
     Array
     (
         [classname1] = Array
                        (
                            delegate11
                            delegate12
                            ...
                        )
         [classnamei] = Array
                        (
                            delegate1i
                            delegate1i
                            ...
                        )
         ...
     )
     Note: If a single classname is passed, a traditional array with numbered
     elements is returned.
  • access: public
  • see: PEAR_Delegator::getDelegateRecursiveExact()
array getDelegateRecursive (class $classname1)
  • class $classname1: This specifies a delegate classname. Any number of arguments after this is acceptable.
getDelegateRecursiveExact (line 544)

Gets the delegate object that is an instance of the specified class.

This method returns classes of the specified type. This does not return subdelegates. This method is provided, because it may be useful, but its use is discouraged, as objects should logically only have access to their native delegates.

  • return:
     The result is an
     associative array of the form:
     Array
     (
         [classname1] = Array
                        (
                            delegate11
                            delegate12
                            ...
                        )
         [classnamei] = Array
                        (
                            delegate1i
                            delegate1i
                            ...
                        )
         ...
     )
     Note: If a single classname is passed, a traditional array with numbered
     elements is returned.
  • access: public
  • see: PEAR_Delegator::getDelegate()
array getDelegateRecursiveExact (class $classname1)
  • class $classname1: This specifies a delegate classname. Any number of arguments after this is acceptable.
getDelegates (line 307)

Gets the associated array of delegate classes => delegates.

Note: Cloning may not work after this.

  • return: A reference to the _delegates array.
  • access: public
array &getDelegates ()
hasDelegate (line 869)

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.
hasDelegateExact (line 920)

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

This returns the availability of a delegate not including subdelegates.

bool hasDelegateExact ([class $specifier = null])
  • class $specifier: This specifies a delegate classname.
is_a (line 1104)

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 1073)

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.

  • return: true if it is, false if it is not.
  • access: public
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 1161)

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 1130)

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.

  • return: true if it is, false if it is not.
  • access: public
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 946)

Removes all delegates.

This completely cleans the calling object of any delegates.

  • access: public
void removeAllDelegates ()
removeDelegate (line 1001)

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.
removeDelegateRecursiveExact (line 1029)

Removes the specified delegate recursively

Only exact delegates are removed, as it would it is otherwise superfluous.

void removeDelegateRecursiveExact (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 getDelegateExact(). If it is an object, then it searches the for that delegate to remove.
respondsToMethod (line 1188)

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 292)

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 1274)

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.

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

Removes an entry from the _method_map array.

This method is for removing entries in the _method_map array. it simply tests for the entry for existence and removes it.

  • return: If entry exists true; false otherwise.
  • access: protected
bool uncacheMathod (string $method)
  • string $method: This method must be in lowercase.
__call (line 1312)

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.

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

Documentation generated on Wed, 10 Mar 2004 16:58:59 -0500 by phpDocumentor 1.3.0RC2