<?php
abstract class BranchDependency
{
private $_dependencies = [];
private $_successors = [];
private $_successful = false;
public final function hasSuccessor(string $name)
{
return array_key_exists($name, $this->getSuccessors());
}
public final function hasDependency(string $name)
{
return array_key_exists($name, $this->getDependencies());
}
public final function getName()
{
return static::class;
}
public final function addDependency(BranchDependency $state)
{
$name = $state->getName();
if (!$this->hasDependency($name)) {
$this->_dependencies[$name] = $state;
$state->addSuccessor($this);
}
}
public final function getDependencies()
{
return $this->_dependencies;
}
public final function addSuccessor(BranchDependency $state)
{
$name = $state->getName();
if (!$this->hasSuccessor($name)) {
$this->_successors[$name] = $state;
$state->addDependency($this);
}
}
public final function getSuccessors()
{
return $this->_successors;
}
public final function wasSuccessful()
{
return $this->_successful;
}
public final function commit()
{
if ($this->run()) {
foreach ($this->getSuccessors() as $successor) {
$successor->commit();
}
}
}
private function run()
{
foreach ($this->getDependencies() as $dependency) {
if (!$dependency->wasSuccessful()) {
return false;
}
}
$this->_successful = $this->execute();
return $this->wasSuccessful();
}
abstract protected function execute();
}
final class BranchDependencyFactory
{
private static $instance = null;
private $_instances = [];
private function __construct() { }
public static function Instance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function exists(string $name)
{
return array_key_exists($name, $this->_instances);
}
public function getUniqueInstance(string $name)
{
if (!$this->exists($name)) {
$this->_instances[$name] = new $name();
}
return $this->_instances[$name];
}
}
final class Internal extends BranchDependency
{
public function __construct(bool $internal)
{
if ($internal) {
$one = BranchDependencyFactory::Instance()->getUniqueInstance(One::class);
$this->addSuccessor($one);
}
$two = BranchDependencyFactory::Instance()->getUniqueInstance(Two::class);
$this->addSuccessor($two);
}
public function execute()
{
return true;
}
}
final class One extends BranchDependency
{
protected function execute()
{
print '#1' . PHP_EOL;
return true;
}
}
final class Two extends BranchDependency
{
public function __construct()
{
$three = BranchDependencyFactory::Instance()->getUniqueInstance(Three::class);
$four = BranchDependencyFactory::Instance()->getUniqueInstance(Four::class);
$this->addSuccessor($three);
$this->addSuccessor($four);
}
protected function execute()
{
print '#2' . PHP_EOL;
return true;
}
}
final class Three extends BranchDependency
{
public function __construct()
{
$five = BranchDependencyFactory::Instance()->getUniqueInstance(Five::class);
$this->addSuccessor($five);
}
protected function execute()
{
print '#3' . PHP_EOL;
return true;
}
}
final class Four extends BranchDependency
{
public function __construct()
{
$five = BranchDependencyFactory::Instance()->getUniqueInstance(Five::class);
$this->addSuccessor($five);
}
protected function execute()
{
print '#4' . PHP_EOL;
return true;
}
}
final class Five extends BranchDependency
{
protected function execute()
{
print '#5' . PHP_EOL;
return true;
}
}
$internal = new Internal(false);
$internal->commit();
Catchable fatal error: Argument 1 passed to Internal::__construct() must be an instance of bool, boolean given, called in /in/5aq5b on line 205 and defined in /in/5aq5b on line 115
Process exited with code 255.