PHP Composite Design Pattern

Composite pattern allows us to treat individual objects (a leaf) and a group of those objects ( a composite) identically.

composite

Leaf defines behavior for primitive objects in the composition. It represents leaf objects in the composition.
Leaf means it has no objects below it.

I can’t grasp idea of Leaf and it’s responsibilty, here is the code example:

<php
interface Honk {
    public function honk();
}

class Car implements Honk {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function honk() {
        echo "$this->name: honk...\n";
    }
}

class CarList implements Honk {
    public $list = [];

    public function add(Car $car) {
        $this->list[] = $car;
    }
    public function honk() {
        foreach ($this->list as $car) {
            $car->honk();
       }
   }
}

$lambo = new Car("Lambo");
$bmw = new Car("BMW");

$list = new CarList();
$list->add($lambo);
$list->add($bmw);

$list->honk();

?>

Typical example of Composite - validators. Any validator should to validate, but also sometimes validators collection required, that should to validate too. I hope, this example help you.

It’s also useful for logging. For example Monlog uses this to log to multiple outputs at the same time:

class Logger
{
   private $handlers;
   public function __construct(array $handlers)
   {
       $this->handlers = $handlers;
   }

   public function log(string $message, int $level): void
   {
       foreach ($this->handlers as $handler) {
          $handler->log($message, $level);
       }
   }
}
interface Handler
{
  public function log(string $message, int $level): void;
}
class FileLogger implement Handler
{
   public function __construct(string $filename)
   {
     $this->filename = $filename;
   }

  public function log(string $message, int $level): void
  {
    file_put_contents($this->filename, sprintf('[%d] %s', $level, $message), FILE_APPEND);
  } 
}
class StdOutLogger implements Handler
{
  public function log(string $message, int $level): void
  {
    $handle = fopen('php://stdout');
    fwrite($handle, sprintf('[%d] %s', $level, $message));
    fclose($handle);
  } 
}

So you can create just 1 logger, pass it a FileLogger and a StdOutLogger and it will write all messages to disk and to screen on standard out.

1 Like

@rpkamp, thanks!

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.