Composite pattern represents the hierarchy of a group of objects in a tree structure. The client can treat a single object and list/group of objects the same way, so it becomes easy for the client.
![](https://bigboxcode.com/wp-content/uploads/2022/12/Composite-Pattern-Composition-Diagram-v3-1024x433.png)
This article describes Composite pattern implementation in PHP. Check the implementation details.
Implementation
Follow the steps below the implement Composite pattern in PHP-
- Create an interface for the item class.
- Create item classes and implement the interface.
- Create composite class(a class to handle a group of items).
- In the composite class maintain a list of the item objects.
- Implement the same item interface for the composite class. In the method implementations loop through the items and perform operations on the item objects.
Here is a simple example of Composite pattern-
<?php
// Composite pattern implemention in PHP
// Item interface
interface Item {
function operation1(): void;
function operation2(): void;
}
// First item class
class Item1 implements Item {
public function operation1(): void {
echo "Item 1: operation 1n";
}
public function operation2(): void {
echo "Item 1: operation 2n";
}
}
// Second item class
class Item2 implements Item {
public function operation1(): void {
echo "Item 2: operation 1n";
}
public function operation2(): void {
echo "Item 2: operation 2n";
}
}
// Composite class
class ItemGroup implements Item {
private array $itemList = [];
public function operation1(): void {
foreach ($this->itemList as $item) {
$item->operation1();
}
}
public function operation2(): void {
foreach ($this->itemList as $item) {
$item->operation2();
}
}
public function addItem(Item $item): void {
array_push($this->itemList, $item);
}
}
// Demo
$item1 = new Item1();
$item2 = new Item2();
$anotherItem1 = new Item1();
$itemGroup = new ItemGroup();
$itemGroup->addItem($item1);
$itemGroup->addItem($item2);
$itemGroup->addItem($anotherItem1);
$itemGroup->operation1();
$itemGroup->operation2();
Output generated by the code above is –
Item 1: operation 1
Item 2: operation 1
Item 1: operation 1
Item 1: operation 2
Item 2: operation 2
Item 1: operation 2
Examples
Check the following Composite pattern examples-
Example #1: Transport List
Transport Interface [Item Interface]
- Create a file “Transport.php”.
- Define interface “Transport”.
- Declare methods as per requirement, here we have -“start”, “stop”, and “operate”.
<?php
// Transport.php
namespace BigBoxCodeDesignPatternCompositeTransportList;
interface Transport {
function start(): void;
function operate(): void;
function stop(): void;
}
Bike Class [Item Class]
- Create a file “Bike.php”.
- Create class “Bike”.
- Implement “Transport” interface for the class.
<?php
// Bike.php
namespace BigBoxCodeDesignPatternCompositeTransportList;
class Bike implements Transport {
public function start(): void {
echo "Starting Bike...n";
}
public function operate(): void {
echo "Riding Biken";
}
public function stop(): void {
echo "Stopping Bike...n";
}
}
Plane Class [Item Class]
- Create a file “Plane.php”.
- Define “Plane” class and implement “Transport” interface for the class.
<?php
// Plane.php
namespace BigBoxCodeDesignPatternCompositeTransportList;
class Plane implements Transport {
public function start(): void {
echo "Starting Plane...n";
}
public function operate(): void {
echo "Flying Planen";
}
public function stop(): void {
echo "Stopping Plane...n";
}
}
Car Class [Item Class]
- Create a file “Car.php”.
- Define “Car” class and implement “Transport” interface.
<?php
// Car.php
namespace BigBoxCodeDesignPatternCompositeTransportList;
class Car implements Transport {
public function start(): void {
echo "Starting Car...n";
}
public function operate(): void {
echo "Driving Carn";
}
public function stop(): void {
echo "Stopping Car...n";
}
}
Composite Class
- Create a file “TransportGroup.php”.
- Define class “TransportGroup”.
- Declare private property “$transportList”, which is an array and will be used to store a list of “Transport” object.
- Implement “Transport” interface for the class.
- In the method implementation loop through the “$transportList” items and call the relevant method. That way the operation will be preformed over all the items of the transport list.
<?php
// TransportGroup.php
namespace BigBoxCodeDesignPatternCompositeTransportList;
class TransportGroup implements Transport {
private array $transportList = [];
public function start(): void {
foreach ($this->transportList as $transport) {
$transport->start();
}
}
public function operate(): void {
foreach ($this->transportList as $transport) {
$transport->operate();
}
}
public function stop(): void {
foreach ($this->transportList as $transport) {
$transport->stop();
}
}
public function addTransport(Transport $transport): void {
array_push($this->transportList, $transport);
}
public function removeTransport(Transport $transport): void {
$elemIndex = array_search($transport, $this->transportList);
if ($elemIndex !== false) {
unset($this->transportList[$elemIndex]);
}
}
}
Demo
Client can create objects, and then add them to the group(or remove them from the group). Then, operation can be performed on the group like an individual object-
<?php
// demo.php
require __DIR__ . '/../../vendor/autoload.php';
use BigBoxCodeDesignPatternCompositeTransportListBike;
use BigBoxCodeDesignPatternCompositeTransportListCar;
use BigBoxCodeDesignPatternCompositeTransportListPlane;
use BigBoxCodeDesignPatternCompositeTransportListTransportGroup;
$bike = new Bike();
$plane = new Plane();
$car = new Car();
$secondCar = new Car();
$transports = new TransportGroup();
$transports->addTransport($bike);
$transports->addTransport($plane);
$transports->addTransport($car);
$transports->addTransport($secondCar);
echo "-----------------Output with 4 transports------------------n";
$transports->start();
$transports->operate();
$transports->stop();
echo "n-----------------Output when plane is removed------------------n";
$transports->removeTransport($plane);
$transports->start();
$transports->operate();
$transports->stop();
Output
The output of the demo above will be like below.
-----------------Output with 4 transports------------------
Starting Bike...
Starting Plane...
Starting Car...
Starting Car...
Riding Bike
Flying Plane
Driving Car
Driving Car
Stopping Bike...
Stopping Plane...
Stopping Car...
Stopping Car...
-----------------Output when plane is removed------------------
Starting Bike...
Starting Car...
Starting Car...
Riding Bike
Driving Car
Driving Car
Stopping Bike...
Stopping Car...
Stopping Car...
Example #2: Player Group
Player Interface [Item Interface]
- Create a file “Player.php”.
- Define interface “Player”.
- Declare method as per requirement, here we have – “printDetails”.
<?php
// Player.php
namespace BigBoxCodeDesignPatternCompositePlayerGroup;
interface Player {
function printDetails(): void;
}
Basketball Player Class [Item Class]
- Create a file “BasketballPlayer.php”.
<?php
// BasketballPlayer.php
namespace BigBoxCodeDesignPatternCompositePlayerGroup;
class BasketballPlayer implements Player {
public function __construct(
private string $name,
private int $age,
private int $point
) {
}
public function printDetails(): void {
echo "nGame: Basketball";
echo "nName: " . $this->name;
echo "nAge: " . $this->age;
echo "nPoints: " . $this->point;
}
}
Football Player Class [Item Class]
- Create a file “FootballPlayer.php”.
<?php
// FootballPlayer.php
namespace BigBoxCodeDesignPatternCompositePlayerGroup;
class FootballPlayer implements Player {
public function __construct(
private string $name,
private int $age,
private int $goal
) {
}
public function printDetails(): void {
echo "nGame: Football";
echo "nName: " . $this->name;
echo "nAge: " . $this->age;
echo "nGoals: " . $this->goal;
}
}
Cricket Player Class [Item Class]
- Create a file “CricketPlayer.php”.
<?php
// CricketPlayer.php
namespace BigBoxCodeDesignPatternCompositePlayerGroup;
class CricketPlayer implements Player {
public function __construct(
private string $name,
private int $age,
private int $run
) {
}
public function printDetails(): void {
echo "nGame: Cricket";
echo "nName: " . $this->name;
echo "nAge: " . $this->age;
echo "nRuns: " . $this->run;
}
}
Player Group
- Create file “PlayerGroup.php”.
<?php
// PlayerGroup.php
namespace BigBoxCodeDesignPatternCompositePlayerGroup;
class PlayerGroup implements Player {
private array $playerList = [];
public function printDetails(): void {
foreach ($this->playerList as $player) {
$player->printDetails();
}
}
public function addElement(Player $player): void {
array_push($this->playerList, $player);
}
public function removeElement(Player $player): void {
$index = array_search($player, $this->playerList);
if ($index !== false) {
unset($this->playerList[$index]);
}
}
}
Demo
Now we can create some player objects and add them to the player group. and then call the “printDetails” method on a single object or the group the same way.
<?php
// demo.php
require __DIR__ . '/../../vendor/autoload.php';
use BigBoxCodeDesignPatternCompositePlayerGroupBasketballPlayer;
use BigBoxCodeDesignPatternCompositePlayerGroupCricketPlayer;
use BigBoxCodeDesignPatternCompositePlayerGroupFootballPlayer;
use BigBoxCodeDesignPatternCompositePlayerGroupPlayerGroup;
// Under 15 players
$under15Players = new PlayerGroup();
$under15Players->addElement(new FootballPlayer("FPlayer 15_1", 13, 23));
$under15Players->addElement(new FootballPlayer("FPlayer 15_2", 14, 30));
$under15Players->addElement(new BasketballPlayer("BPlayer 15_1", 12, 80));
$under15Players->addElement(new BasketballPlayer("BPlayer 15_2", 14, 100));
$under15Players->addElement(new CricketPlayer("CPlayer 15_1", 14, 467));
// Under 19 Players
$under19Players = new PlayerGroup();
$under19Players->addElement(new FootballPlayer("FPlayer 19_1", 18, 43));
$under19Players->addElement(new BasketballPlayer("BPlayer 19_1", 17, 77));
$under19Players->addElement(new CricketPlayer("CPlayer 19_1", 18, 654));
$under19Players->addElement(new CricketPlayer("CPlayer 19_2", 16, 789));
// National team players
$nationalTeamPlayers = new PlayerGroup();
$nationalTeamPlayers->addElement(new FootballPlayer("FPlayer N_1", 18, 43));
$nationalTeamPlayers->addElement(new BasketballPlayer("BPlayer N_1", 17, 77));
$nationalTeamPlayers->addElement(new CricketPlayer("CPlayer N_1", 18, 654));
// Create a group with all teams
$allTeams = new PlayerGroup();
$allTeams->addElement($under15Players);
$allTeams->addElement($under19Players);
$allTeams->addElement($nationalTeamPlayers);
// Print details of all players
// from each game and group
$allTeams->printDetails();
Output
We will get the following output-
Game: Football
Name: FPlayer 15_1
Age: 13
Goals: 23
Game: Football
Name: FPlayer 15_2
Age: 14
Goals: 30
Game: Basketball
Name: BPlayer 15_1
Age: 12
Points: 80
Game: Basketball
Name: BPlayer 15_2
Age: 14
Points: 100
Game: Cricket
Name: CPlayer 15_1
Age: 14
Runs: 467
Game: Football
Name: FPlayer 19_1
Age: 18
Goals: 43
Game: Basketball
Name: BPlayer 19_1
Age: 17
Points: 77
Game: Cricket
Name: CPlayer 19_1
Age: 18
Runs: 654
Game: Cricket
Name: CPlayer 19_2
Age: 16
Runs: 789
Game: Football
Name: FPlayer N_1
Age: 18
Goals: 43
Game: Basketball
Name: BPlayer N_1
Age: 17
Points: 77
Game: Cricket
Name: CPlayer N_1
Age: 18
Runs: 654
Example #3: Menu
Menu Interface
- Create a file “Menu.php”.
- Define interface “Menu”.
- Declare method “print” for printing menu item.
<?php
// Menu.php
namespace BigBoxCodeDesignPatternCompositeMenu;
interface Menu {
function print(): void;
}
Menu Item Class
- Create a file “MenuItem.php”.
- Define class “MenuItem”.
- Define properties for storing the link and the text for the link.
- Implement interface “Menu” for the class.
- In the “print” method implementation, print the menu item as per requirement.
<?php
// MenuItem.php
namespace BigBoxCodeDesignPatternCompositeMenu;
class MenuItem implements Menu {
public function __construct(private string $link, private string $text) {
}
public function print(): void {
echo "[li][a link='" . $this->link . "']" . $this->text . "[/a][/li]n";
}
}
Menu Item Group
- Create file “MenuParent.php”.
- Define class “MenuParent”.
- Define property “$menuItem” to store a list of “Menu”.
- Implement interface “Menu”.
- In the “print” method implementation, loop through all the items in the list and call “print” method of those objects.
- Define method for adding and removing items to the list.
<?php
// MenuParent.php
namespace BigBoxCodeDesignPatternCompositeMenu;
class MenuParent implements Menu {
private array $menuItems = [];
public function print(): void {
echo "[ul]n";
foreach ($this->menuItems as $menuItem) {
$menuItem->print();
}
echo "[ul]n";
}
public function addItem(Menu $menuItem): void {
array_push($this->menuItems, $menuItem);
}
public function removeItem(Menu $menuItem): void {
$itemIndex = array_search($menuItem, $this->menuItems);
if ($itemIndex !== false) {
unset($this->menuItems, $itemIndex);
}
}
}
Demo
In the client we can create object of –
- Menu Item (MenuItem)
- A group of Menu items.
- A nested group of menu items, where a group of items belong to another parent group of items.
<?php
// demo.php
require __DIR__ . '/../../vendor/autoload.php';
use BigBoxCodeDesignPatternCompositeMenuMenuItem;
use BigBoxCodeDesignPatternCompositeMenuMenuParent;
// Define some menu items
$item1 = new MenuItem("http://firstlink.com", "First Item");
$item2 = new MenuItem("http://secondlink.com", "Second Item");
$item3 = new MenuItem("http://thirdlink.com", "Third Item");
// Define a group of items
$itemGroup1 = new MenuParent();
$itemGroup1->addItem(new MenuItem("http://group-item-1.com", "First group item"));
$itemGroup1->addItem(new MenuItem("http://group-item-2.com", "Second group item"));
$itemGroup1->addItem(new MenuItem("http://group-item-3.com", "Third group item"));
$itemGroup1->addItem(new MenuItem("http://group-item-4.com", "Fourth group item"));
$item4 = new MenuItem("http://item-4.com", "4th Item");
// Add items to menu
$mainMenu = new MenuParent();
$mainMenu->addItem($item1);
$mainMenu->addItem($item2);
$mainMenu->addItem($item3);
$mainMenu->addItem($itemGroup1);
$mainMenu->addItem($item4);
// Print menu
$mainMenu->print();
Output
Output will be as below-
[ul]
[li][a link='http://firstlink.com']First Item[/a][/li]
[li][a link='http://secondlink.com']Second Item[/a][/li]
[li][a link='http://thirdlink.com']Third Item[/a][/li]
[ul]
[li][a link='http://group-item-1.com']First group item[/a][/li]
[li][a link='http://group-item-2.com']Second group item[/a][/li]
[li][a link='http://group-item-3.com']Third group item[/a][/li]
[li][a link='http://group-item-4.com']Fourth group item[/a][/li]
[ul]
[li][a link='http://item-4.com']4th Item[/a][/li]
[ul]
Source Code
Use the following link to get the source code:
Example | Source Code Link |
---|---|
Example #1: Transport List | ![]() |
Example #2: Player Group | ![]() |
Example #3: Menu | ![]() |
Other Code Implementations
Use the following links to check Composite pattern implementation in other programming languages.