Use the Visitor Design Pattern | PHP Code Examples in 2023

Last Updated on

CraftyTechie is reader-supported. When you buy through links on our site, we may earn an affiliate commission.

Using the Visitor Design Pattern in PHP

The visitor pattern is a behavioral pattern that separates algorithms from the objects it operates on. This distinction helps minimize changes to the existing system and conveniently introduces new behaviors or variants of behavior to the system.

Article Highlights

  • Visitor pattern helps in the separation of concerns between behaviors (algorithms) and objects they act on.
  • Benefit – Add additional behaviors (algorithms) to a complex composite without changing it.
  • Con – A visitor class is coupled to the base classes it operates on.
  • Use when you need to separate the business and presentational layers in an application.
<?php

interface Visitor {

    public function menuInfo($menu);
    public function menuItemInfi($menuItem);
}

class NutrientInfoVisitor implements Visitor {

    //Expects Menu object
   public function menuInfo($menu) {
       /*
       Iterate through menu items and provide information on every menu item.
       */
   }


   //Expects MenuItem object.
   public function menuItemInfo($menuItem) {
       /*
           Provide nutrient information of the menuitem
       */
   }

}

class Menu implements MenuComponent{

    //All other methods

    //Expects a visitor object
    public function accept($visitor) {
        $visitor->menuInfo($this); //Passes Menu object using this reference.
    }
}

class MenuItem implements MenuComponent {

    //All other methods

    //Expects a visitor object
    public function accept($visitor) {
        $visitor->menuInfo($this); //Passes Menu object using this reference.
    }
}

function main() {

    $nutrientInfoVisitor = new NutrientInfoVisitor();

    foreach($menuComponents as $menuComponent) {
        $menuComponent->accept($nutrientInfoVisitor); //The object can call appropriate visitor method now.
    }

}

?>
Visitor Design Pattern in PHP

This article revisits the FoodNet application, where we need to change the system to comply with a new business requirement. This change has stirred a debate within teams, where the existing system is at stake.

What is the Visitor Design Pattern

“The visitor pattern is a behavioral design pattern that separates algorithms from the objects it operates on.”

Visitor Design Pattern in PHP

Visitor Design Pattern Example

Remember FoodNet from the Composite and Iterator design pattern articles? This article revisits it because there is a time for a new change, and the teams are caught between a rock and a hard place. We will see that in the following sections, but it is important to understand what FoodNet is.

So, FoodNet is an application that shows information about all the eateries in a certain radius around your location. It is a cool application and has been scaled enormously over time. Last time we left off with a solution that dealt with composition or tree models.

However, we don’t intend to include that detail here because it has already been sorted out in the Composite design pattern. Rather, let’s look through the composite more generically. It had parent Menu and child MenuItem classes. Though a Menu can include nested menus, and thus, the tree can repeat itself but again, not a concern here.

Generally, a Menu and MenuItem occurs as follows.

menu-menuitem-tree

Nice! Now let’s see what change request has been put forward that has our teams run out of road.

Problem 🙁

Health regulatory authority has enforced a new law by which we must provide nutritional information about the meals. 

Developers propose adding methods in the existing classes to cater to this requirement. The product team is unwilling to change the existing system, possibly breaking things that have been working just fine. They just cannot afford to do so.

no-change

The product team is right, though. The proposed solution has downsides from a design point of view.

Open-closed Principle

“A class should be closed for modification but open for extension”, says the open-closed principle. Modifying existing classes opens up new ways for bugs to creep in. One change can blow up an application in production and potentially cause financial losses if you have a customer-centric application similar to FoodNet.

So, the product team was right when they vehemently opposed the proposal of adding functionalities to existing fragile systems. But there is yet another aspect to this problem that too violates this principle.

The current change request wants to add a behavior to Menu and MenuItem so that they can provide nutritional information. Suppose that we have more change requests like these in the future. Would we prefer to add those to the existing system?

Not because we would end up modifying existing systems, potentially breaking them. Also, we will bloat up our classes with unrelated responsibilities, which is the second problem. 

Single Responsibility Principle

“A class should do one and only one thing” or “A class should have only one reason to change” is the single responsibility principle. It is a principle for creating highly cohesive, specialized classes. A highly cohesive class is not a jack of all trades, so you don’t have to change it that often.

So, are Menu and MenuItem classes supposed to provide nutrient information when their sole responsibility is to model their real-life counterparts? The answer is negative. 

That’s why adding methods to the existing classes affects the degree of their cohesion.

Solution 🙂

Software architects and developers racked their brains all day and ended up with a pretty interesting solution statement. Do you want to hear?

“If you can’t bring a behaviour to a class, bring a class to a behavior”.

What does that mean? The solution suggests separating behaviors (algorithms) and the objects it operates on.

In the FoodNet example, we may have methods for providing nutrient information in a class called NutrientInfo, and these methods can accept Menu and MenuItem objects, respectively.


The following pseudocode provides some context on NutrientInfo class.

<?php


class NutrientInfo {


   //Expects Menu object
   public function menuInfo($menu) {
       /*
       Iterate through menu items and provide information on every menu item.
       */
   }


   //Expects MenuItem object.
   public function menuItemInfo($menuItem) {
       /*
           Provide nutrient information of the menuitem
       */
   }
?>

We are heading somewhere, but there is a problem still. How do we call these methods, especially when dealing with a complex menu and sub-menus? Here’s a glimpse of calling these methods on a composite.

<?php


// MenuComponent is a generic node which may be either a Menu or a MenuItem
foreach($menuComponents as $menuComponent) {


   $nutrientInfoProvider = new NutrientInfo();


   //Check if it is a Menu object and then call the appropriate method
   if(menuComponent instanceof Menu) {
       $nutrientInfoProvider->menuInfo($menuComponent);
   }


   //Else check it is a MenuItem object.
   if(menuComponent instanceof MenuItem) {
       $nutrientInfoProvider->menuItemInfo($menuComponent);
   }
}


?>

Yikes! See the type checks. They are a huge setback from a design perspective. Consider the due changes following any additional or removal to the composite or the behavior itself. Besides, they are already ugly and will bloat the client code.

Are we back to square zero? Does this solution go to the bin too? Hmmm, not really. We have a visitor that will help us here.

Introducing Visitor Pattern in PHP

Visitor pattern features the idea of a Visitor, which not only includes the methods we have seen already but also goes around the problem of conditional type checks using a technique known as Double Dispatch

A visitor pays a visit to every class. The class can call methods on the visitor, invoking the appropriate functions. Because a class knows its type, it is easy to pick the right method without causing compile or runtime issues.

visitor-object

Instead of type checks in the client code, these objects call the methods, meaning we have to add a method to Menu and MenuItem. Yes, it is a trade-off. Still, the change itself is small and isolated. It won’t affect any other part of these classes. 

Implementing Visitor Design Pattern in PHP

A Visitor interface helps use concrete visitor(s) polymorphically. As a concrete implementation, we have NutrientInfoVisitor, which has a similar implementation as seen already.

<?php
interface Visitor {


   public function menuInfo($menu);
   public function menuItemInfo($menuItem);
}


class NutrientInfoVisitor implements Visitor {


   //Expects Menu object
  public function menuInfo($menu) {
      /*
      Iterate through menu items and provide information on every menu item.
      */
  }




  //Expects MenuItem object.
  public function menuItemInfo($menuItem) {
      /*
          Provide nutrient information of the menuitem
      */
  }


}


?>


Up next, we add a method accept() to the Menu and MenuItem classes, which expects a Visitor object and calls the appropriate visitor method.

class Menu implements MenuComponent{


   //All other methods


   //Expects a visitor object
   public function accept($visitor) {
       $visitor->menuInfo($this); //Passes Menu object using this reference.
   }
}


class MenuItem implements MenuComponent {


   //All other methods


   //Expects a visitor object
   public function accept($visitor) {
       $visitor->menuInfo($this); //Passes Menu object using this reference.
   }
}

Now, the client code can initialize a Visitor and let the objects deal with the rest as follows.

function main() {


   $nutrientInfoVisitor = new NutrientInfoVisitor();


   foreach($menuComponents as $menuComponent) {
       $menuComponent->accept($nutrientInfoVisitor); //The object can call the appropriate visitor method now.
   }


}

Benefits of the Visitor Design Pattern

  • Separate business logic from the presentational layer by separating behaviors.
  • Add or remove behaviors without changing the structure.
  • Define many variants of behavior using different concrete visitors.
  • Have a centralized location for business logic or behavioral code in your application.
  • Visitors can easily integrate with complex composite structures.

Complete Architecture | Visitor Design Pattern in PHP

Visitor Design Pattern in PHP

Visitor Design Pattern PHP Pseudocode Example

<?php


interface Visitor {


   public function menuInfo($menu);
   public function menuItemInfi($menuItem);
}


class NutrientInfoVisitor implements Visitor {


   //Expects Menu object
  public function menuInfo($menu) {
      /*
      Iterate through menu items and provide information on every menu item.
      */
  }




  //Expects MenuItem object.
  public function menuItemInfo($menuItem) {
      /*
          Provide nutrient information of the menuitem
      */
  }


}


class Menu implements MenuComponent{


   //All other methods


   //Expects a visitor object
   public function accept($visitor) {
       $visitor->menuInfo($this); //Passes Menu object using this reference.
   }
}


class MenuItem implements MenuComponent {


   //All other methods


   //Expects a visitor object
   public function accept($visitor) {
       $visitor->menuInfo($this); //Passes Menu object using this reference.
   }
}


function main() {


   $nutrientInfoVisitor = new NutrientInfoVisitor();


   foreach($menuComponents as $menuComponent) {
       $menuComponent->accept($nutrientInfoVisitor); //The object can call the appropriate visitor method now.
   }


}


?>

Pros and Cons of the Visitor Pattern in PHP

ProsCons
Satisfies the open-closed principle because we can add as many visitors without modifying the existing code.Visitors are coupled with the base classes. They have to be changed if the base classes change.
Satisfies the single responsibility principle because behaviors are separated from the base classes.Changes to the composite structure become more difficult
Easily add behaviors without changing existing classes.
A visitor can traverse a complex structure and accumulate state information from different types of objects in it.

Where is the Visitor Pattern Used?

You can use the visitor pattern in PHP when you want to:

  • Attach a behavior to objects in a composite without affecting the structure itself.
  • Separate business logic from presentational logic.
  • Implement different variants of business logic or an algorithm.
  • Define different behaviors for different object types.

Frequently Asked Questions on the Visitor Design Pattern

What is the visitor pattern?

The visitor pattern is a behavioral pattern that separates algorithms from the objects it operates on.

This distinction helps minimize changes to the existing system and conveniently introduces new behaviors or variants of behavior to the system.

What is double dispatch in visitor pattern?

Double dispatch in software engineering helps choose the right method to call based on their runtime types. A compiler is not confident about the types of objects before runtime, so calling an overloaded method can cause the compiler to pick the wrong method. 

Visitor pattern uses double dispatch by delegating method calls to the concrete object, which helps the compiler call the correct version of the overloaded method in the visitor.

Note that PHP doesn’t support method overloading the way other programming languages like Java and C# do, and that’s why we use different methods. Yet the visitor pattern in PHP helps with the issue of having too many type checks in the client code.

Using the Visitor Pattern in PHP Today

Voila! That’s all about the visitor pattern in PHP. Let’s review what we have seen thus far. The visitor pattern is a behavioral pattern that separates algorithms from the objects it operates on. Separating behaviors helps minimize code changes to an existing system and also helps in defining and attaching behaviors independently to the system.

The article revisits the FoodNet application, where a new regulatory rule has been introduced. The application is supposed to display nutritional information about the food. Given the change request, developers propose a solution that is simply adding methods to existing classes.

The product team doesn’t want to modify the fragile system and thus doesn’t see eye to eye with developers.

Consequently, architects propose a solution that separates the existing system and the required behavior. They do so, but they are faced with yet another problem of extensive type checking code in the client code.

Finally, they reach a solution which is the visitor pattern. Visitor pattern uses the double dispatch concept. Visitors define methods and delegate method invocation responsibility to the objects themselves. 

Visitor pattern helps eliminate the type checking code and makes the system more flexible and extensible in terms of adding behaviors or variants of a behavior.

One powerful use of double dispatch and visitor pattern is the separation of concerns, a fundamental principle in software design and clean coding practices.

That’s all. See you in another design pattern article. Stay tuned at FuelingPHP.

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.

Learn the Fundamentals of Good Web Development

Please take a moment and sign up for our free email course on the fundamentals of good web development. Every week is packed with a roundup of articles on our site and from around the web, where we go deep into developing exceptional web applications. We have meetups, code reviews, slack chats, and more.

Click here to get started

Did you find this article helpful?

Join the best weekly newsletter where I deliver content on building better web applications. I curate the best tips, strategies, news & resources to help you develop highly-scalable and results-driven applications.

Build Better Web Apps

I hope you're enjoying this article.

Get the best content on building better web apps delivered to you.