Make your own free website on Tripod.com
    We will create 10 classes: 
        A
            ADelegate1
            ADelegate2
            B
                BDelegate1
                BDelegate2.
        Extra1
        Extra2
        Traditional
            Delegate
            DelegateFalse
            DelegateMixed;
    
    They are defined as follows:
    
    class A extends PEAR_Delegator
    {
        var $message;
        
        public function __construct()
        {
            parent::__construct();
            
            $this->addDelegate(ADelegate1);
            $this->addDelegate(ADelegate2);
            $this->addDelegate(new B);
        }
        
        public function __destruct()
        {
            parent::__destruct();
        }
    }
    
    class ADelegate1 extends PEAR
    {
        public function __construct()
        {
        }
        
        public function __destruct()
        {
        }
        
        public function setMessage1($owner, $message)
        {
            $owner->message = $message;
        }
    }
    
    class ADelegate2 extends PEAR
    {
        public function __construct()
        {
        }
        
        public function __destruct()
        {
        }
        
        public function getMessage1($owner)
        {
            echo $owner->message;
        }
    }
    
    class B extends PEAR_Delegator
    {
        public function __construct()
        {
            parent::__construct();
            
            $this->addDelegate(BDelegate1);
            $this->addDelegate(BDelegate2);
        }
        
        public function __destruct()
        {
            parent::__destruct();
        }
        
        function foo()
        {
            echo get_class($this) . ": I will now call my foo delegate without knowing which one it is< BR>";
            
            $args = func_get_args();
            
            $this->forwardMethod("foo", $args);
        }
        
        function bar()
        {
            echo get_class($this) . ": I will now call my bar delegate without knowing which one it is< BR>";
            
            $args = func_get_args();
            
            $this->forwardMethod("bar", $args);
        }
                
        public function setMessage2($owner, $message)
        {
            $this->message = $message;
        }
        
        public function getMessage2()
        {
            echo $this->message;
        }
    }
    
    class BDelegate1 extends PEAR
    {
        public function __construct()
        {
        }
        
        public function __destruct()
        {
        }
        
        public function foo()
        {
            echo "BDelegate1:" . ": foo< BR>";
        }
    }
    
    class BDelegate2 extends PEAR
    {
        public function __construct()
        {
        }
        
        public function __destruct()
        {
        }
        
        public function bar()
        {
            echo "BDelegate2" . ": bar< BR>";
        }
    }
    
    class Extra1 extends PEAR_Delegator
    {
        public function __construct()
        {
            parent::__construct();
        }
        
        public function __destruct()
        {
            parent::__destruct();
        }
        
        public function awesome1()
        {
            echo "Isn't this Awesome!";
        }
    }
    
    class Extra2
    {
        public function __construct()
        {
        }
        
        public function __destruct()
        {
        }
        
        public function awesome2()
        {
            echo "Really, isn't this Awesome!";
        }
    }
    
    class Traditional extends PEAR_Delegator
    {
        public function __construct()
        {
            parent::__construct();
        }
        
        public function __destruct()
        {
            parent::__destruct();
        }
        
        public function showList()
        {
            $args = func_get_args();
            
            if ($this->hasDelegate())
            {
                return $this->forwardMethod("showList", $args);
            }
            
            echo $args[0];
            
            unset($args[0]);
            
            foreach ($args as $arg)
            {
                echo ", $arg";
            }
        }
    }
    
    class Delegate
    {
        var $_multiplier;
        
        public function __construct($number)
        {
            $this->_multiplier = $number;
        }
        
        public function __destruct()
        {
        }
        
        public function showList($owner)
        {
            $args = func_get_args();
            
            echo $args[1] * $this->_multiplier;
            
            unset($args[0]);
            unset($args[1]);
            
            foreach ($args as $arg)
            {
                echo ", " . $arg * $this->_multiplier;
            }
        }
    }
    
    class DelegateFalse
    {
        public function showListFalse($multiplier)
        {
            $args = func_get_args();
            
            echo  * $multiplier;
            
            unset($args[0]);
            unset($args[1]);
            
            foreach ($args as )
            {
                echo  . $arg * ;
            }
        }
    }
    
    class DelegateMixed extends PEAR_Delegator
    {
        public function __construct()
        {            
            $this->addDelegate(false, DelegateFalse);
        }
        
        public function showList($owner)
        {
            echo "My owner, $owner, says \"Show the list!\" But I don't want to show no stinking list!";
        }
    }
    Before we get into the really cool stuff, here is the traditional delegate model:
    
    We instantiate our Traditional class and call its showList method:
    
    $Traditional = new Traditional;
    
    $Traditional->showList(1, 2, 3, 4, 5);
    Output:
1, 2, 3, 4, 5
    Let us now augment this method with our Delegate. We instantiate the
    Delegate class:
    
    $Delegate = new Delegate(2); //value 2 sets multiplier of list;
    
    In the traditional model, only one delegate can be used, so:
    
    $Traditional->setDelegate($Delegate);  //Note, static delegates are also applicable.
    
    $Traditional->showList(1, 2, 3, 4, 5);
    Output:
2, 4, 6, 8, 10
    Thus, the delegate method is called instead.
    
    
    There is also support for existing classes, called false delegates, whose methods don't
    take the delegator as their first arguments:
    $Traditional->addDelegate(false, DelegateFalse);
    $Traditional->showListFalse(3, 1, 2, 3, 4, 5);
3, 6, 9, 12, 15
    In this way, mixed false and true methods can be used.
    First, lets set the delegate to the mixed version:
    $Traditional->setDelegate(DelegateMixed);
    $Traditional->showListFalse(3, 1, 2, 3, 4, 5);
3, 6, 9, 12, 15
    $Traditional->showList(1, 2, 3, 4, 5);
My owner, Object id #1, says "Show the list!" But I don't want to show no stinking list!
    
    
    
    We now instantiate an A object:
    
    $A = new A;
    
    You'll note that the A class defines no useable method. Nevertheless,
    when we call $A->setMessage1("Hello"), we get no error.
    
    To prove that it worked, let's recall the message with
    
    $A->getMessage1();
    
    Output:
Hello
    Let's now set and get the second message:
    
    $A->setMessage2("World");
    $A->getMessage2();
    
    Output:
World
    You'll note that the second message is not even stored in the A object!
    
    Now, let's try some of the other methods:
    
    //This calls the method foo in B which calls the method in BDelegate1, albeit transparently.
    $A->foo();
    Output:
B: I will now call my foo delegate without knowing which one it is
BDelegate1:: foo
    //This calls the method bar in B which calls the method in BDelegate2, albeit transparently.
    $A->bar();
    Output:
B: I will now call my bar delegate without knowing which one it is
BDelegate2: bar
    You'll also notice that we simply instantiated A, which added the delegates to itself
    in its constructor. This is convenient, but it is certainly not the only way to add delegates.
    In fact, delegates can be added to a delegator at any time, and with classname or object.
    Let's add another delegate to A through an object:
    
    //We add this as an object, because it needs access to instance variables. If a delegate only
    //supplies static methods, then it can be added statically (by classname), in which no object
    //is created.
    $Extra1 = new Extra1;
    $A->addDelegate($Extra1);
    
    We can now call the methods in Extra1 on the A object as follows:
    
    $A->awesome1();
    Output:
Isn't this Awesome!
    Here, we add a new delegate to the Extra1 object by classname:
    
    $Extra1->addDelegate(Extra2);
    
    Now we can use the methods in Extra2 on the A object as follows:
    
    $A->awesome2();
    Output:
Really, isn't this Awesome!
    Now, let's explore the features of the PEAR_Delegate class. This class deals
    solely with the method forwarding mechanism and the delegate class hierarchy.
    Thus, all of its methods reflect that function.
    
    We have demonstrated the ability to add more delegates and so on, so we will
    now sequentially go though the other methods.
    
    It is generally necessary to have access to the delegate hierarchy, so we have
    getDelegate*() methods.
    
    To view the results, we will define a few functions along the way.
    
    function print_r_ElementTypes($array)
    {
        foreach ($array as $key => $element)
            echo "[$key] => " . get_class($element) . "< BR>";
    }
    
    print_r_ElementTypes($A->getAllDelegates());
    Output:
[ADelegate1] => ADelegate1
[ADelegate2] => ADelegate2
[B] => B
[Extra1] => Extra1
    We can immediately see that this is the correct output of native delegates to the A Object.
    
    Now let's search for one particular kind of native delegate:
    
    print_r_ElementTypes($A->getDelegate(PEAR));
    output:
[0] => ADelegate1
[1] => ADelegate2
[2] => B
    Or perhaps:
    
    print_r_ElementTypes($A->getDelegate(PEAR_Delegator));
    output:
[0] => B
[1] => Extra1
    We can even search for multiple classes at a time:
    
    function print_r_ElementTypesR($array)
    {
        foreach ($array as $key => $element)
        {
            echo "[$key]\n";
            foreach ($element as $delegate)
            {
                echo "	" . get_class($delegate) . "\n";
            }
        }
    }
    
    echo "< PRE>\n";
    print_r_ElementTypesR($A->getDelegate(PEAR, PEAR_Delegator, B, BDelegate1));
    echo "< /PRE>\n";
    output:
[PEAR]
	ADelegate1
	ADelegate2
	B
[PEAR_Delegator]
	B
	Extra1
[B]
	B
[BDelegate1]
	B
    You'll notice that BDelegate1 returned B. This is an example of delegate subclassing.
    
    Now, let's add the extensions to the class:
    
    $A->addExtensions();
    
    We can do the same thing for a delegate of the exact type:
    
    echo $A->getDelegateExact(BDelegate1);
    Output:
    Nothing! There is no delegate directly of the type BDelegate1, so nothing is returned.
    
    Conversely,
    
    print_r_ElementTypesR($A->getDelegateExact(PEAR));
    Output:
[0] => ADelegate1
[1] => ADelegate2
    We can ask for multiple classes as well:
    
    echo "< PRE>\n";
    print_r_ElementTypesR($A->getDelegateExact(PEAR, B, ADelegate1, ADelegate2));
    echo "< /PRE>\n";
    Output:
[PEAR]
	ADelegate1
	ADelegate2
[B]
	B
[ADelegate1]
	ADelegate1
[ADelegate2]
	ADelegate2
    While one should only have access to the native delegates, methods are provided for
    delving deeper into the inheritance hierarchy.
    
    For instance:
    
    print_r_ElementTypes($A->getDelegateRecursive(PEAR));
[0] => ADelegate1
[1] => ADelegate2
[2] => BDelegate1
[3] => BDelegate2
[4] => B
    This also handles requests for multiple classes:
    
    echo "< PRE>\n";
    print_r_ElementTypes($A->getDelegateRecursive(PEAR, PEAR_Delegator, B, BDelegate1));
    echo "< /PRE>\n";
    output:
[PEAR]
	ADelegate1
	ADelegate2
	BDelegate1
	BDelegate2
	B
[PEAR_Delegator]
	B
	Extra1
[B]
	B
[BDelegate1]
	BDelegate1
	B
    We likewise have a recursive exact method:
    
    echo "< PRE>\n";
    print_r_ElementTypesR($A->getDelegateRecursiveExact(PEAR, PEAR_Delegator, B, BDelegate1));
    echo "< /PRE>\n";
    Output:
[PEAR]
	ADelegate1
	ADelegate2
[PEAR_Delegator]
	B
	Extra1
[B]
	B
[BDelegate1]
	BDelegate1
    We can also fetch the native delegate that can resond to a particular method:
    
    echo "< PRE>\n";
    print_r_ElementTypesR($A->getDelegateForMethod("foo", "bar", "awesome1", "awesome2", "addDelegate"));
    echo "< /PRE>\n";
    Output:
[foo]
	B
[bar]
	B
[awesome1]
	Extra1
[awesome2]
	Extra1
[addDelegate]
	B
	Extra1
    You can also get the first native responder found (native delegates are return in favor of nonnative):
    
    print_r_ElementTypes($A->getDelegateForMethodFirst("addDelegate", "notAMethod"));
    Output:
[addDelegate] => B
    The second argument makes the output an array, but if one argument is passed, the object is returned:
    
    echo get_class($A->getDelegateForMethodFirst("awesome2"));
    Output:
Extra1
    There are also recursive methods for getting delegates that respond to a particular method:
    
    echo "< PRE>\n";
    print_r_ElementTypesR($A->getDelegateForMethodRecursive("foo","bar", "awesome1", "awesome2", "addDelegate"));
    echo "< /PRE>\n";
    Output:
[foo]
	BDelegate1
	B
[bar]
	BDelegate2
	B
[awesome1]
	Extra1
[awesome2]
	Extra2
	Extra1
[addDelegate]
	B
	Extra1
    We can get the delegates that actually implement (or naturally inherit) the methods too:
    
    echo "< PRE>\n";
    print_r_ElementTypesR($A->getDelegateForMethodRecursiveExact("foo","bar", "awesome1", "awesome2", "addDelegate"));
    echo "< /PRE>\n";
    Output:
[foo]
	B
	BDelegate1
[bar]
	B
	BDelegate2
[awesome1]
	Extra1
[awesome2]
	Extra2
[addDelegate]
	B
	Extra1
    We can get the delegates that actually implement one method too:
    
    echo "< PRE>\n";
    print_r_ElementTypes($A->getDelegateForMethodRecursiveExact("foo"));
    echo "< /PRE>\n";
    Output:
[0] => B
[1] => BDelegate1
    Much like you can use the instanceof operator to test for the kind of class, you
    can test for the kind of delegate inheritance an object has:
    
    echo ($A->hasDelegate(B)) ? "yes" : "no";
    Output:
yes
    This also takes into account delegates lower in the hierarchy:
    
    echo ($A->hasDelegate(BDelegate1)) ? "yes" : "no";
    Output:
yes
    You can also determine if a delegate of a specific class is available:
    
    echo ($A->hasDelegateExact(BDelegate1)) ? "yes" : "no";
    Output:
no
    But,
    
    echo ($A->hasDelegateExact(B)) ? "yes" : "no";
    Output:
yes
    These methods only test the delegates though. You can actually invoke a delegate-aware
    version of the is_a() function on any object:
    
    echo (PEAR_Delegator::is_a($A, PEAR_Delegator)) ? "yes" : "no";
    Output:
yes
    or:
    
    echo (PEAR_Delegator::is_a($A, Extra2)) ? "yes" : "no";
    Output:
yes
    This method also recognizes classes:
    
    echo (PEAR_Delegator::is_a(PEAR_Delegator, PEAR)) ? "yes" : "no";
    Output:
no
    There is also the is_aExact() method, but this is invoked when is_a() is called,
    so it is mostly used internally.
    
    You can also test whether or not an object implements a certain method, whether
    native or not:
    
    echo ($A->respondsToMethod("awesome3")) ? "yes" : "no";
    Output:
no
    Or,
    
    echo ($A->respondsToMethod("awesome2")) ? "yes" : "no";
    Output:
yes
    This actually calls an extension of method_exists(), which handles
    class objects as well:
    
    echo (PEAR_Delegator::method_exists(Extra2, "awesome2")) ? "yes" : "no";
    Output:
yes
    There are also methods for removing delegates.
    
    For instance:
    
    $A->removeDelegate(Extra2, ADelegate2);
    echo "< PRE>";
    print_r($A->getAllDelegates())
    echo "< /PRE>";
    Output:
Array
(
    [ADelegate1] => ADelegate1
    [B] => B Object
        (
            [_delegates] => Array
                (
                    [BDelegate1] => BDelegate1
                    [BDelegate2] => BDelegate2
                )

            [_delegatesFalse] => Array
                (
                )

            [_method_map] => Array
                (
                    [foo] => BDelegate1
                    [bar] => BDelegate2
                )

            [_forwardingDelegator] => B Object
 *RECURSION*
            [message] => World
        )

    [PEAR_Delegator_Extensions] => PEAR_Delegator_Extensions Object
        (
        )

)
    You'll notice the proper delegates are gone.
    
    We can also remove delegates recursively, though only exact delegates
    can be removed in this fashion, because it is superfluous otherwise:
    
    $A->removeDelegateRecursiveExact(BDelegate2);
    echo "< PRE>";
    print_r($A->getAllDelegates())
    echo "< /PRE>";
    Output:
Array
(
    [ADelegate1] => ADelegate1
    [B] => B Object
        (
            [_delegates] => Array
                (
                    [BDelegate1] => BDelegate1
                )

            [_delegatesFalse] => Array
                (
                )

            [_method_map] => Array
                (
                    [foo] => BDelegate1
                )

            [_forwardingDelegator] => B Object
 *RECURSION*
            [message] => World
        )

    [PEAR_Delegator_Extensions] => PEAR_Delegator_Extensions Object
        (
        )

)
    We can also remove all of the delegates:
    
    $A->removeAllDelegates();
    
    Now we can't call any delegate method (there should be a very specific error):
    
    $A->setMessage1();
    Output:
Fatal error: Call to undefined method A::setMessage1() in /Users/michael/Sites/OldSites/DelegatorTest.php on line 1086