Skip to content
Home » Use the Mediator Design Pattern | PHP Code Examples in 2023

Use the Mediator Design Pattern | PHP Code Examples in 2023

Using the Mediator Pattern in PHP

The mediator pattern is a behavioral design pattern that simplifies the complex relationship between objects and lets them communicate indirectly via a mediator object.

Article Highlights

  • The mediator object helps reduce the complex dependencies between the entities by acting as a central entity of control.
  • Benefit – Reduces coupling between entities and simplifies their relationship.

Mediator Design Pattern PHP Code Example

Mediator Pattern PHP
<?php

interface Mediator {

    public function send($file, $sender, $exception);
    public function receive($file);
}

class SharingMediator implements Mediator {

    private $peers; //Array of users (peers)

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

    public function send($file, $sender, $exception) {
            
        //1. Apply business logic.
        //2. Apply exception.
        //3. Send file to peers.
    }

    public function receive($file, $peer) {
        //1. Apply business logic
        //2. Receive file from a sender
    }
}


class User {

    private $id;    //User identifier
    private $name;  //User name
    private $mediator; //Mediator object

    public function __construct($peers) {
        $this->mediator = new SharingMediator($peers);
    }
    
    public function addPeer($peer) {
        
        if(!($peer instanceof User)) {
            throw new Exception('Not a user');
        } 
    }

    public function send($file, $exception) {

        $this->mediator->send($file, $this, $exception);

    }

    public function receive($file) {

        //Receive files from senders.
    }

}

class Exception {

    private $exceptionType; //Exception name
    private $allowedPeers; //Whitelist peers in an exception

    public function __construct() {
        $this->exceptionType = 'Default';
        $this->allowedPeers = [];
    }

    public function addPeer($peer) {

        if(!($peer instanceof User)) {
            throw new Exception('Not a user');
        } 

        $this->allowedPeers[] = $peer; //Adds to the array of peers
    }

    public function setExceptionType($type) {
        $this->exceptionType = $type;
    }
    
    public function getException() {
        return $this->allowedPeers;
    }

    public function getExceptionType() {
        return $this->exceptionType;
    }
}


?>

Table of Contents

What is the Mediator Pattern

The mediator pattern is a behavioral design pattern that simplifies the complex relationship between objects and lets them communicate indirectly via a mediator object.

Mediator Pattern PHP

Mediator Pattern Example

PeerShare is a file-sharing application that lets you transfer files seamlessly and securely.  Users can create peer groups, define exceptions and send data based on these exceptions. The application is based on a fairly simplistic idea.   

A user, Alice, wants to share files with her peers, Bob, Tom & Harry. File A should be shared with all of them. File B has to be shared with Tom & Harry only, and File C has to be shared with Harry only. 

Alice has defined the following exceptions based on her usual sharing pattern:

  • All (Default)
  • Tom&Harry (Rules out Bob) 
  • Harry (Rules out Bob & Tom)

The following illustration shows how the files are shared, given the exceptions.

file-share

There is a dependency graph between the sender and peers. Also, peers can be senders, so these entities have a many-to-many relationship.

many-to-many

If you think the graph is scary, you have seen nothing yet because the solution is about to be equally confusing and gibberish.

Not convinced? Let’s review the pseudocode of a typical User class.

<?php


class User {


   private $id;    //User identifier
   private $name;  //User naem
   private $peers; //Array of users (peers)


   public function __construct() {
       $this->peers = [];
   }
  
   public function addPeer($peer) {
      
       if(!($peer instanceof User)) {
           throw new Exception('Not a user');
       }


       $this->peers[] = $peer; //Adds to the array of peers
   }


   public function send($file, $exception) {


       //Send file with exception rule applied.


   }


   public function receive($file) {


       //Receive files from senders.
   }


}


class Exception {


   private $exceptionType; //Exception name
   private $allowedPeers; //Whitelist peers in an exception


   public function __construct() {
       $this->exceptionType = 'Default';
       $this->allowedPeers = [];
   }


   public function addPeer($peer) {


       if(!($peer instanceof User)) {
           throw new Exception('Not a user');
       }


       $this->allowedPeers[] = $peer; //Adds to the array of peers
   }


   public function setExceptionType($type) {
       $this->exceptionType = $type;
   }
   public function getException() {
       return $this->allowedPeers;
   }


   public function getExceptionType() {
       return $this->exceptionType;
   }
}




?>

Can’t see the problems in the pseudocode right away? A few design-related concerns could be a pain point in the future.

Problem 🙁

Single Responsibility principle

“A class should have one and only one responsibility.”, states the single responsibility principle. The User class communicates with peers under some exception rules. Though nothing is wrong with it, logically speaking, placing this responsibility in the User class affects the class’s cohesiveness.

A better alternative would be extracting communications between the entities in a separate class. User class would then be more specialized. When something changes concerning how the entities communicate, we won’t have to revisit the User but the class, which has the functionality for establishing or relaying the communications.

Open-closed principle

“A class should be closed for modification but open for extension.”, states the open/closed principle. Currently, the User class is tightly bound to the concrete instances of its type. The communication between the entities is dependent on the logic which is there in the User class.

Programming to concrete instances and a lack of interface generally indicates a lousy software design. The current design would be hard to crack when new entities are introduced, or something changes in the existing business logic.

Complex entity relationships

The entities have a many-to-many relationship, making the dependencies and communications much more complex and, thus, difficult to track. The nature of this dependency relationship also tightly bounds entities reducing their reusability and increasing code duplication.

A nice solution would be adding a centralized control mechanism to localize the communication logic and sufficiently decrease complexity.

Solution 🙂

Centralized logic

Having a centralized entity that could relay the communication between the entities would simplify the relationship complexity and serve a single point of logic related to the control logic. 

Any change or addition to the control logic will be limited to the centralized entity. Using this approach will make our system easy to change. Any new communication protocol will affect the central entity. User and any other classes would be relatively reusable and relatively free of the central logic.

The mediator

We will call the centralized entity “mediator” (thus the pattern’s name). The mediator lies between the entities, and the request goes through it before reaching the target entity. The User objects are thus loosely coupled and don’t know much about each other. 

mediator

The mediator has the entire control logic. So, when communication logic changes, we know exactly where to look.

interface Mediator {


   public function send($file, $sender, $exception);
   public function receive($file);
}


class SharingMediator implements Mediator {


   private $peers; //Array of users (peers)


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


   public function send($file, $sender, $exception) {
          
       //1. Apply business logic.
       //2. Apply the exception.
       //3. Send a file to peers.
   }


   public function receive($file, $peer) {
       //1. Apply business logic
       //2. Receive file from a sender
   }
}

The User class would have a reference to a mediator. The mediator object controls the entire communication. Understand the full example through the pseudocode.

Benefits of the Mediator Pattern

  • Decouples the entities of software to make them more usable.
  • Simplifies complex relationships between entities.
  • Centralized the core logic to open the application to changes and modification.

Complete Architecture | Mediator Pattern in PHP

Mediator Pattern PHP

Mediator Pattern PHP Pseudocode Example

<?php

interface Mediator {

    public function send($file, $sender, $exception);
    public function receive($file);
}

class SharingMediator implements Mediator {

    private $peers; //Array of users (peers)

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

    public function send($file, $sender, $exception) {
            
        //1. Apply business logic.
        //2. Apply exception.
        //3. Send file to peers.
    }

    public function receive($file, $peer) {
        //1. Apply business logic
        //2. Receive file from a sender
    }
}


class User {

    private $id;    //User identifier
    private $name;  //User name
    private $mediator; //Mediator object

    public function __construct($peers) {
        $this->mediator = new SharingMediator($peers);
    }
    
    public function addPeer($peer) {
        
        if(!($peer instanceof User)) {
            throw new Exception('Not a user');
        } 
    }

    public function send($file, $exception) {

        $this->mediator->send($file, $this, $exception);

    }

    public function receive($file) {

        //Receive files from senders.
    }

}

class Exception {

    private $exceptionType; //Exception name
    private $allowedPeers; //Whitelist peers in an exception

    public function __construct() {
        $this->exceptionType = 'Default';
        $this->allowedPeers = [];
    }

    public function addPeer($peer) {

        if(!($peer instanceof User)) {
            throw new Exception('Not a user');
        } 

        $this->allowedPeers[] = $peer; //Adds to the array of peers
    }

    public function setExceptionType($type) {
        $this->exceptionType = $type;
    }
    
    public function getException() {
        return $this->allowedPeers;
    }

    public function getExceptionType() {
        return $this->exceptionType;
    }
}


?>

Pros and Cons of the Mediator Pattern in PHP

ProsCons
Satisfies the single responsibility principle by separating the communication logic from the User class.The mediator object can become overly complex if the design is not well thought out.
Satisfies open-closed principle by introducing mediator object and decoupling User entities.The mediator object can sometimes become the all-knowing object.
Increases the usability of the User class.
Reduces coupling between entities and simplifies their relationship.
Centralized logic eases the maintenance and change process.

Where is the Mediator Pattern Used

  • Designing reusable UI components by delegating event handling to the mediator object.
  • Simplify complex relationships, usually many-to-many relationships, by introducing the mediator object.
  • Use a mediator when an object is overly dependent on another object to the extent that it affects its usability.

What is the Mediator Pattern

The mediator pattern is a behavioral design pattern that simplifies the complex relationship between objects and lets them communicate indirectly via a mediator object.

Using the Mediator Pattern in PHP Today

That’s about it. Let’s overview the information in this article. The mediator pattern is a behavioral design pattern that simplifies the complex relationship between objects and lets them communicate indirectly via a mediator object.

This article features a file-sharing application defining peer groups where users can send files. The application also features exceptions or rules based on which the user can decide who should or shouldn’t receive a certain file.

The Users are related by a many-to-many relationship in which any User can be a sender to other peer users. Given the nature of this application, the initial design programs a many-to-many relationship that creates tight coupling between user entities. Also, the design becomes very rigid to changes.

Therefore, a centralized entity solves the problem by placing the control logic in one place, freeing up the User class from communication and control logic. As a result, it simplifies the relationship’s complexity.

The user entities now communicate indirectly via a mediator object. This design helps a lot when change requests kick in because the control logic is not over the place and also increases the reusability of the User class because it is now more cohesive and acts more independently.

That’s all. See you in another design pattern article.

Books on Design Patterns

Want to learn more about Design Patterns? There are many great resources online. We recommend the following books for your collection as they both can teach you the theoretical and the application of using design patterns in your day-to-day programming. Feel free to use the following Amazon affiliate links if you’d like to purchase them and a way to support our efforts.

Design Patterns: Elements of Reusable Object-Oriented Software

Design Patterns: Elements of Reusable Object-Oriented Software book

This is the book that started it all. I believe that every programmer should have a referenced copy to this book at some point in their career. There have been many updates and excellent newer content through the years, but this is a classic. It still stands the test of time and is just as relevant for today as it was in the original printing in the 90s.

Check it out on amazon

Learning PHP Design Patterns

This is an excellent book to go beyond the theory and apply it to writing good PHP code. Learning PHP Design Patterns is published by the popular O’Reilly media company. O’Reilly consistently publishes some of the most useful reference material related to software development. They are known to provide materials that thoroughly cover a topic in a way that is simple to understand. I recommend this book to every PHP developer.

Check it out on amazon

Want to see our full review of books on design patterns? Read our huge review article on over 15 design pattern books.

Design Patterns in PHP Learning Series.

This article is part of our series of design patterns in PHP. We are going through all of the patterns and showing how they can help you build better applications. Browse through our full list of patterns below.