PHP Decorator Pattern Example

Fri, 22 Oct 2010

Here is a simple PHP Decorator Pattern Example. Go ahead and dissect this script to see how it works. A decorator pattern is exactly what it sounds like, it decorates! So in this example we'll make a cupcake that we add items onto, and this changes the instance of the original object -- and we don't need to extend a ton of classes!

By playing around with this basic thing, you should be able to learn by simple example. I hope it helps anyone learning OOD!

<?php

// 1. Our base object that gets decorations on it
class Cupcake
{
	public $Toppings = array('sprinkles' => 0, 'frosting' => 'none');
	
	public function __construct($int, $str)
	{
		$this->Toppings['sprinkles'] = $int;
		$this->Toppings['frosting'] = $str;
	}
}

// 2. Just a nice little wrapper to keep the decorators consistent!
abstract class Decorator_Wrapper
{
	abstract function Add($mixed);
	abstract function Remove($mixed);
}

// 3. A decorator that manipulates our main object!
class Sprinkle_Decorator extends Decorator_Wrapper
{
	public function __construct(Cupcake $c)
	{
		$this->Cupcake = $c;
	}
	
	public function Add($int)
	{
		$this->Cupcake->Toppings['sprinkles'] += $int;
	}
	
	public function Remove($int)
	{
		$this->Cupcake->Toppings['sprinkles'] -= $int;
	}
	
}

// 4. Another decorator that manipulates our main object!
class Frosting_Decorator extends Decorator_Wrapper
{
	public function __construct(Cupcake $c)
	{
		$this->Cupcake = $c;
	}
	
	public function Add($str)
	{
		$this->Cupcake->Toppings['frosting'] = $str;
	}
	
	public function Remove($str)
	{
		echo "Hrmm.. We cant seem to remove your $str, it's stuck on the muffin!";
	}
	
}

// Run through some tests to satisfy our customer!
echo '<p>Mmm! I want a cupcake!</p>';
$cupcake = new Cupcake(5, 'none');
print_r($cupcake->Toppings);


echo '<p>Hey, I want more sprinkles!</p>' ;
$sprinkle = new Sprinkle_Decorator($cupcake);
$sprinkle->Add('55');
print_r($cupcake->Toppings);


echo '<p>Not so many!</p>' ;
$sprinkle->Remove('25');
print_r($cupcake->Toppings);


echo '<p>If only I had some frosting :)</p>';
$frosting = new Frosting_Decorator($cupcake);
$frosting->Add('Chocolate');
print_r($cupcake->Toppings);

And here's the output!

Mmm! I want a cupcake!

Array ( [sprinkles] => 5 [frosting] => none )

Hey, I want more sprinkles!

Array ( [sprinkles] => 60 [frosting] => none )

Not so many!

Array ( [sprinkles] => 35 [frosting] => none )

If only I had some frosting :)

Array ( [sprinkles] => 35 [frosting] => Chocolate )

And here's a video explaining the pattern some more!