1. <?php
    2. interface Entity
    3. {
    4. public function accept(Visitor $visitor): string;
    5. }
    6. class Company implements Entity
    7. {
    8. private $name;
    9. /**
    10. * @var Department[]
    11. */
    12. private $departments;
    13. public function __construct(string $name, array $departments)
    14. {
    15. $this->name = $name;
    16. $this->departments = $departments;
    17. }
    18. public function getName(): string
    19. {
    20. return $this->name;
    21. }
    22. public function getDepartments(): array
    23. {
    24. return $this->departments;
    25. }
    26. public function accept(Visitor $visitor): string
    27. {
    28. return $visitor->visitCompany($this);
    29. }
    30. }
    31. class Department implements Entity
    32. {
    33. private $name;
    34. /**
    35. * @var Employee[]
    36. */
    37. private $employees;
    38. public function __construct(string $name, array $employees)
    39. {
    40. $this->name = $name;
    41. $this->employees = $employees;
    42. }
    43. public function getName(): string
    44. {
    45. return $this->name;
    46. }
    47. public function getEmployees(): array
    48. {
    49. return $this->employees;
    50. }
    51. public function getCost(): int
    52. {
    53. $cost = 0;
    54. foreach ($this->employees as $employee) {
    55. $cost += $employee->getSalary();
    56. }
    57. return $cost;
    58. }
    59. public function accept(Visitor $visitor): string
    60. {
    61. return $visitor->visitDepartment($this);
    62. }
    63. }
    64. class Employee implements Entity
    65. {
    66. private $name;
    67. private $position;
    68. private $salary;
    69. public function __construct(string $name, string $position, int $salary)
    70. {
    71. $this->name = $name;
    72. $this->position = $position;
    73. $this->salary = $salary;
    74. }
    75. public function getName(): string
    76. {
    77. return $this->name;
    78. }
    79. public function getPosition(): string
    80. {
    81. return $this->position;
    82. }
    83. public function getSalary(): int
    84. {
    85. return $this->salary;
    86. }
    87. public function accept(Visitor $visitor): string
    88. {
    89. return $visitor->visitEmployee($this);
    90. }
    91. }
    92. interface Visitor
    93. {
    94. public function visitCompany(Company $company): string;
    95. public function visitDepartment(Department $department): string;
    96. public function visitEmployee(Employee $employee): string;
    97. }
    98. class SalaryReport implements Visitor
    99. {
    100. public function visitCompany(Company $company): string
    101. {
    102. $output = "";
    103. $total = 0;
    104. foreach ($company->getDepartments() as $department) {
    105. $total += $department->getCost();
    106. $output .= "\n--" . $this->visitDepartment($department);
    107. }
    108. $output = $company->getName() .
    109. " (" . money_format("%i", $total) . ")\n" . $output;
    110. return $output;
    111. }
    112. public function visitDepartment(Department $department): string
    113. {
    114. $output = "";
    115. foreach ($department->getEmployees() as $employee) {
    116. $output .= " " . $this->visitEmployee($employee);
    117. }
    118. $output = $department->getName() .
    119. " (" . money_format("%i", $department->getCost()) . ")\n\n" .
    120. $output;
    121. return $output;
    122. }
    123. public function visitEmployee(Employee $employee): string
    124. {
    125. return money_format("%#6n", $employee->getSalary()) .
    126. " " . $employee->getName() .
    127. " (" . $employee->getPosition() . ")\n";
    128. }
    129. }
    130. /**
    131. * The client code.
    132. */
    133. $mobileDev = new Department("Mobile Development", [
    134. new Employee("Albert Falmore", "designer", 100000),
    135. new Employee("Ali Halabay", "programmer", 100000),
    136. new Employee("Sarah Konor", "programmer", 90000),
    137. new Employee("Monica Ronaldino", "QA engineer", 31000),
    138. new Employee("James Smith", "QA engineer", 30000),
    139. ]);
    140. $techSupport = new Department("Tech Support", [
    141. new Employee("Larry Ulbrecht", "supervisor", 70000),
    142. new Employee("Elton Pale", "operator", 30000),
    143. new Employee("Rajeet Kumar", "operator", 30000),
    144. new Employee("John Burnovsky", "operator", 34000),
    145. new Employee("Sergey Korolev", "operator", 35000),
    146. ]);
    147. $company = new Company("SuperStarDevelopment", [$mobileDev, $techSupport]);
    148. setlocale(LC_MONETARY, 'en_US');
    149. $report = new SalaryReport();
    150. echo "Client: I can print a report for a whole company:\n\n";
    151. echo $company->accept($report);
    152. echo "\nClient: ...or just for a single department:\n\n";
    153. echo $techSupport->accept($report);
    154. // $export = new JSONExport();
    155. // echo $company->accept($export);

    output

    1. Client: I can print a report for a whole company:
    2. SuperStarDevelopment (USD550,000.00)
    3. --Mobile Development (USD351,000.00)
    4. $100,000.00 Albert Falmore (designer)
    5. $100,000.00 Ali Halabay (programmer)
    6. $ 90,000.00 Sarah Konor (programmer)
    7. $ 31,000.00 Monica Ronaldino (QA engineer)
    8. $ 30,000.00 James Smith (QA engineer)
    9. --Tech Support (USD199,000.00)
    10. $ 70,000.00 Larry Ulbrecht (supervisor)
    11. $ 30,000.00 Elton Pale (operator)
    12. $ 30,000.00 Rajeet Kumar (operator)
    13. $ 34,000.00 John Burnovsky (operator)
    14. $ 35,000.00 Sergey Korolev (operator)
    15. Client: ...or just for a single department:
    16. Tech Support (USD199,000.00)
    17. $ 70,000.00 Larry Ulbrecht (supervisor)
    18. $ 30,000.00 Elton Pale (operator)
    19. $ 30,000.00 Rajeet Kumar (operator)
    20. $ 34,000.00 John Burnovsky (operator)
    21. $ 35,000.00 Sergey Korolev (operator)