Visitor Design Pattern in PHP

In the Visitor pattern, one class calls a function in another class with the current instance of itself. The called class has special functions for each class that can call it.

In this example, the BookVisitee can call the visitBook function in any function extending the Visitor class. By doing this new Visitors which format the BookVisitee information can easily be added without changing the BookVisitee at all.

<?php

abstract class Visitee {
    abstract function accept(Visitor $visitorIn);
}

class BookVisitee extends Visitee {
    private $author;
    private $title;
    function __construct($title_in, $author_in) {
        $this->author = $author_in;
        $this->title  = $title_in;
    }
    function getAuthor() {return $this->author;}
    function getTitle() {return $this->title;}
    function accept(Visitor $visitorIn) {
        $visitorIn->visitBook($this);
    }
}

class SoftwareVisitee extends Visitee {
    private $title;
    private $softwareCompany;
    private $softwareCompanyURL;
    function __construct($title_in, $softwareCompany_in, $softwareCompanyURL_in) {
        $this->title  = $title_in;
        $this->softwareCompany = $softwareCompany_in;
        $this->softwareCompanyURL = $softwareCompanyURL_in;
    }
    function getSoftwareCompany() {return $this->softwareCompany;}
    function getSoftwareCompanyURL() {return $this->softwareCompanyURL;}
    function getTitle() {return $this->title;}
    function accept(Visitor $visitorIn) {
        $visitorIn->visitSoftware($this);
    }
}

abstract class Visitor {
    abstract function visitBook(BookVisitee $bookVisitee_In);
    abstract function visitSoftware(SoftwareVisitee $softwareVisitee_In);
}

class PlainDescriptionVisitor extends Visitor {  
    private $description = NULL;
    function getDescription() {
        return $this->description;
    }
    function setDescription($descriptionIn) { 
        $this->description = $descriptionIn;
    }
    function visitBook(BookVisitee $bookVisiteeIn) {
        $this->setDescription($bookVisiteeIn->getTitle().'. written by '.$bookVisiteeIn->getAuthor());
    }
    function visitSoftware(SoftwareVisitee $softwareVisiteeIn) {
        $this->setDescription($softwareVisiteeIn->getTitle().
           '. made by '.$softwareVisiteeIn->getSoftwareCompany().
           '. website at '.$softwareVisiteeIn->getSoftwareCompanyURL());
    }
}

class FancyDescriptionVisitor extends Visitor {
    private $description = NULL;
    function getDescription() { return $this->description; }
    function setDescription($descriptionIn) { 
      $this->description = $descriptionIn;
    }
    function visitBook(BookVisitee $bookVisiteeIn) {
        $this->setDescription($bookVisiteeIn->getTitle().
            '...!*@*! written !*! by !@! '.$bookVisiteeIn->getAuthor());
    }
    function visitSoftware(SoftwareVisitee $softwareVisiteeIn) {
        $this->setDescription($softwareVisiteeIn->getTitle().
            '...!!! made !*! by !@@! '.$softwareVisiteeIn->getSoftwareCompany().
            '...www website !**! at http://'.$softwareVisiteeIn->getSoftwareCompanyURL());
    }
}

  writeln('BEGIN TESTING VISITOR PATTERN');
  writeln('');
 
  $book = new BookVisitee('Design Patterns', 'Gamma, Helm, Johnson, and Vlissides');
  $software = new SoftwareVisitee('Zend Studio', 'Zend Technologies', 'www.zend.com');

  $plainVisitor = new PlainDescriptionVisitor();
 
  acceptVisitor($book,$plainVisitor);
  writeln('plain description of book: '.$plainVisitor->getDescription());
  acceptVisitor($software,$plainVisitor);
  writeln('plain description of software: '.$plainVisitor->getDescription());
  writeln('');
 
  $fancyVisitor = new FancyDescriptionVisitor();
 
  acceptVisitor($book,$fancyVisitor);
  writeln('fancy description of book: '.$fancyVisitor->getDescription());
  acceptVisitor($software,$fancyVisitor);
  writeln('fancy description of software: '.$fancyVisitor->getDescription());

  writeln('END TESTING VISITOR PATTERN');

  //double dispatch any visitor and visitee objects
  function acceptVisitor(Visitee $visitee_in, Visitor $visitor_in) {
    $visitee_in->accept($visitor_in);
  }

  function writeln($line_in) {
    echo $line_in."<br/>";
  }

?>

Output

BEGIN TESTING VISITOR PATTERN

plain description of book: Design Patterns
. written by Gamma, Helm, Johnson, and Vlissides
plain description of software: Zend Studio
. made by Zend Technologies
. website at www.zend.com

fancy description of book: Design Patterns
...!*@*! written !*! by !@! Gamma, Helm, Johnson, and Vlissides
fancy description of software: Zend Studio
...!!! made !*! by !@@! Zend Technologies
...www website !**! at http://www.zend.com

END TESTING VISITOR PATTERN

Code examples