Skip to content

Commit 1c30978

Browse files
committed
PHP7 Visitor
1 parent 19fff0a commit 1c30978

9 files changed

Lines changed: 72 additions & 149 deletions

File tree

Behavioral/README.md

Lines changed: 0 additions & 19 deletions
This file was deleted.

Behavioral/Visitor/Group.php

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,25 @@
22

33
namespace DesignPatterns\Behavioral\Visitor;
44

5-
/**
6-
* An example of a Visitor: Group.
7-
*/
8-
class Group extends Role
5+
class Group implements Role
96
{
107
/**
118
* @var string
129
*/
13-
protected $name;
10+
private $name;
1411

15-
/**
16-
* @param string $name
17-
*/
18-
public function __construct($name)
12+
public function __construct(string $name)
1913
{
20-
$this->name = (string) $name;
14+
$this->name = $name;
2115
}
2216

23-
/**
24-
* @return string
25-
*/
26-
public function getName()
17+
public function getName(): string
18+
{
19+
return sprintf('Group: %s', $this->name);
20+
}
21+
22+
public function accept(RoleVisitorInterface $visitor)
2723
{
28-
return 'Group: '.$this->name;
24+
$visitor->visitGroup($this);
2925
}
3026
}

Behavioral/Visitor/README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ RoleVisitorInterface.php
3131
:language: php
3232
:linenos:
3333

34-
RolePrintVisitor.php
34+
RoleVisitor.php
3535

36-
.. literalinclude:: RolePrintVisitor.php
36+
.. literalinclude:: RoleVisitor.php
3737
:language: php
3838
:linenos:
3939

Behavioral/Visitor/Role.php

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,7 @@
22

33
namespace DesignPatterns\Behavioral\Visitor;
44

5-
/**
6-
* class Role.
7-
*/
8-
abstract class Role
5+
interface Role
96
{
10-
/**
11-
* This method handles a double dispatch based on the short name of the Visitor.
12-
*
13-
* Feel free to override it if your object must call another visiting behavior
14-
*
15-
* @param \DesignPatterns\Behavioral\Visitor\RoleVisitorInterface $visitor
16-
*
17-
* @throws \InvalidArgumentException
18-
*/
19-
public function accept(RoleVisitorInterface $visitor)
20-
{
21-
// this trick to simulate double-dispatch based on type-hinting
22-
$klass = get_called_class();
23-
preg_match('#([^\\\\]+)$#', $klass, $extract);
24-
$visitingMethod = 'visit'.$extract[1];
25-
26-
// this ensures strong typing with visitor interface, not some visitor objects
27-
if (!method_exists(__NAMESPACE__.'\RoleVisitorInterface', $visitingMethod)) {
28-
throw new \InvalidArgumentException("The visitor you provide cannot visit a $klass instance");
29-
}
30-
31-
call_user_func(array($visitor, $visitingMethod), $this);
32-
}
7+
public function accept(RoleVisitorInterface $visitor);
338
}

Behavioral/Visitor/RolePrintVisitor.php

Lines changed: 0 additions & 27 deletions
This file was deleted.

Behavioral/Visitor/RoleVisitor.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace DesignPatterns\Behavioral\Visitor;
4+
5+
class RoleVisitor implements RoleVisitorInterface
6+
{
7+
/**
8+
* @var Role[]
9+
*/
10+
private $visited = [];
11+
12+
public function visitGroup(Group $role)
13+
{
14+
$this->visited[] = $role;
15+
}
16+
17+
public function visitUser(User $role)
18+
{
19+
$this->visited[] = $role;
20+
}
21+
22+
/**
23+
* @return Role[]
24+
*/
25+
public function getVisited(): array
26+
{
27+
return $this->visited;
28+
}
29+
}

Behavioral/Visitor/RoleVisitorInterface.php

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,12 @@
33
namespace DesignPatterns\Behavioral\Visitor;
44

55
/**
6-
* Visitor Pattern.
7-
*
8-
* The contract for the visitor.
9-
*
10-
* Note 1 : in C++ or Java, with method polymorphism based on type-hint, there are many
11-
* methods visit() with different type for the 'role' parameter.
12-
*
13-
* Note 2 : the visitor must not choose itself which method to
14-
* invoke, it is the Visitee that make this decision.
6+
* Note: the visitor must not choose itself which method to
7+
* invoke, it is the Visitee that make this decision
158
*/
169
interface RoleVisitorInterface
1710
{
18-
/**
19-
* Visit a User object.
20-
*
21-
* @param \DesignPatterns\Behavioral\Visitor\User $role
22-
*/
2311
public function visitUser(User $role);
2412

25-
/**
26-
* Visit a Group object.
27-
*
28-
* @param \DesignPatterns\Behavioral\Visitor\Group $role
29-
*/
3013
public function visitGroup(Group $role);
3114
}

Behavioral/Visitor/Tests/VisitorTest.php

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,34 @@
44

55
use DesignPatterns\Behavioral\Visitor;
66

7-
/**
8-
* VisitorTest tests the visitor pattern.
9-
*/
107
class VisitorTest extends \PHPUnit_Framework_TestCase
118
{
12-
protected $visitor;
9+
/**
10+
* @var Visitor\RoleVisitor
11+
*/
12+
private $visitor;
1313

1414
protected function setUp()
1515
{
16-
$this->visitor = new Visitor\RolePrintVisitor();
16+
$this->visitor = new Visitor\RoleVisitor();
1717
}
1818

19-
public function getRole()
19+
public function provideRoles()
2020
{
21-
return array(
22-
array(new Visitor\User('Dominik'), 'Role: User Dominik'),
23-
array(new Visitor\Group('Administrators'), 'Role: Group: Administrators'),
24-
);
21+
return [
22+
[new Visitor\User('Dominik')],
23+
[new Visitor\Group('Administrators')],
24+
];
2525
}
2626

2727
/**
28-
* @dataProvider getRole
28+
* @dataProvider provideRoles
29+
*
30+
* @param Visitor\Role $role
2931
*/
30-
public function testVisitSomeRole(Visitor\Role $role, $expect)
32+
public function testVisitSomeRole(Visitor\Role $role)
3133
{
32-
$this->expectOutputString($expect);
3334
$role->accept($this->visitor);
34-
}
35-
36-
/**
37-
* @expectedException \InvalidArgumentException
38-
* @expectedExceptionMessage Mock
39-
*/
40-
public function testUnknownObject()
41-
{
42-
$mock = $this->getMockForAbstractClass('DesignPatterns\Behavioral\Visitor\Role');
43-
$mock->accept($this->visitor);
35+
$this->assertSame($role, $this->visitor->getVisited()[0]);
4436
}
4537
}

Behavioral/Visitor/User.php

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,25 @@
22

33
namespace DesignPatterns\Behavioral\Visitor;
44

5-
/**
6-
* Visitor Pattern.
7-
*
8-
* One example for a visitee. Each visitee has to extends Role
9-
*/
10-
class User extends Role
5+
class User implements Role
116
{
127
/**
138
* @var string
149
*/
15-
protected $name;
10+
private $name;
1611

17-
/**
18-
* @param string $name
19-
*/
20-
public function __construct($name)
12+
public function __construct(string $name)
2113
{
22-
$this->name = (string) $name;
14+
$this->name = $name;
2315
}
2416

25-
/**
26-
* @return string
27-
*/
28-
public function getName()
17+
public function getName(): string
18+
{
19+
return sprintf('User %s', $this->name);
20+
}
21+
22+
public function accept(RoleVisitorInterface $visitor)
2923
{
30-
return 'User '.$this->name;
24+
$visitor->visitUser($this);
3125
}
3226
}

0 commit comments

Comments
 (0)