This pattern lets you outsource operations on objects to other objects. The main reason to do this is to keep a separation of concerns. But classes have to define a contract to allow visitors. The contract is an abstract class but you can have also a clean interface. In that case, each Visitor has to choose itself which method to invoke on the visitor.
Role.php
<?php
namespace Kuriv\PHPDesignPatterns\Behavioral\Visitor;
interface Role
{
/**
* Allow role access.
*
* @param RoleVisitor $visitor
* @return void
*/
public function access(RoleVisitor $visitor);
}User.php
<?php
namespace Kuriv\PHPDesignPatterns\Behavioral\Visitor;
class User implements Role
{
/**
* Store the name.
*
* @var string
*/
private string $name;
/**
* Store the name to the current instance.
*
* @param string $name
* @return void
*/
public function __construct(string $name)
{
$this->name = $name;
}
/**
* Allow role access.
*
* @param RoleVisitor $visitor
* @return void
*/
public function access(RoleVisitor $visitor)
{
$visitor->recordUser($this);
}
}Group.php
<?php
namespace Kuriv\PHPDesignPatterns\Behavioral\Visitor;
class Group implements Role
{
/**
* Store the name.
*
* @var string
*/
private string $name;
/**
* Store the name to the current instance.
*
* @param string $name
* @return void
*/
public function __construct(string $name)
{
$this->name = $name;
}
/**
* Allow role access.
*
* @param RoleVisitor $visitor
* @return void
*/
public function access(RoleVisitor $visitor)
{
$visitor->recordGroup($this);
}
}RoleVisitor.php
<?php
namespace Kuriv\PHPDesignPatterns\Behavioral\Visitor;
interface RoleVisitor
{
/**
* Record user access.
*
* @param User $role
* @return void
*/
public function recordUser(User $user);
/**
* Record group access.
*
* @param Group $role
* @return void
*/
public function recordGroup(Group $group);
}RecordVisitor.php
<?php
namespace Kuriv\PHPDesignPatterns\Behavioral\Visitor;
class RecordVisitor implements RoleVisitor
{
/**
* Store the access record.
*
* @var array
*/
private array $record = [];
/**
* Record user access.
*
* @param User $role
* @return void
*/
public function recordUser(User $role)
{
$this->record[] = $role;
}
/**
* Record group access.
*
* @param Group $role
* @return void
*/
public function recordGroup(Group $role)
{
$this->record[] = $role;
}
/**
* Get all the records.
*
* @param void
* @return array
*/
public function getRecord(): array
{
return $this->record;
}
}VisitorTest.php
<?php
namespace Kuriv\PHPDesignPatterns\Behavioral\Visitor;
use PHPUnit\Framework\TestCase;
class VisitorTest extends TestCase
{
public function testVisitSomeRole()
{
$visitor = new RecordVisitor();
$user = new User('Kuriv');
$user->access($visitor);
$this->assertSame($user, $visitor->getRecord()[0]);
$group = new Group('Administrators');
$group->access($visitor);
$this->assertSame($group, $visitor->getRecord()[1]);
}
}