[英]PHP Nesting functions OOP
我正在使用一个库,它具有以下过程来将许多操作附加到一个事件
$action = (new EventBuilder($target))->addOperation($Operation1)->addOperation($Operation2)->addOperation($Operation3)->compile();
我不确定如何根据我需要做的事情动态添加操作。
像这样的东西
$action = (new EventBuilder($target));
while (some event)
{
$action = $action->addOperation($OperationX);
}
$action->compile();
我需要能够在 while 循环中动态添加操作,并在所有操作都添加后运行它。
先感谢您
您提出的解决方案将起作用。 EventBuilder 提供了所谓的Fluent Interface ,这意味着有一些方法可以返回构建器本身的实例,允许您根据需要多次调用addOperation
,然后调用compile
方法来产生结果。 但是,您可以随意忽略addOperation
的返回值,只要您有一个包含最终可以调用compile
的构建器实例的变量。
和我一起散步...
// Some boilerplate classes to work with
class Target
{
private ?string $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function getName(): string
{
return $this->name;
}
}
class Operation
{
private ?string $verb;
public function __construct(string $verb)
{
$this->verb = $verb;
}
public function getVerb(): string
{
return $this->verb;
}
}
class Action
{
private ?Target $target;
private array $operations = [];
public function __construct(Target $target, array $operations)
{
$this->target = $target;
$this->operations = $operations;
}
/**
* Do the things
* @return array
*/
public function run(): array
{
$output = [];
foreach ($this->operations as $currOperation)
{
$output[] = $currOperation->getVerb() . ' the ' . $this->target->getName();
}
return $output;
}
}
以下是您的 EventBuilder 在幕后所做的基本解释:
class EventBuilder
{
private ?Target $target;
private array $operations = [];
public function __construct(Target $target)
{
$this->target = $target;
}
/**
* @param Operation $operation
* @return $this
*/
public function addOperation(Operation $operation): EventBuilder
{
$this->operations[] = $operation;
// Fluent interface - return a reference to the instance
return $this;
}
public function compile(): Action
{
return new Action($this->target, $this->operations);
}
}
让我们尝试这两种技术并证明它们会产生相同的结果:
// Mock some operations
$myOperations = [
new Operation('Repair'),
new Operation('Clean'),
new Operation('Drive')
];
// Create a target
$target = new Target('Car');
/*
* Since the EventBuilder implements a fluent interface (returns an instance of itself from addOperation),
* we can chain the method calls together and just put a call to compile() at the end, which will return
* an Action instance
*/
$fluentAction = (new EventBuilder($target))
->addOperation($myOperations[0])
->addOperation($myOperations[1])
->addOperation($myOperations[2])
->compile();
// Run the action
$fluentResult = $fluentAction->run();
// Traditional approach, create an instance and call the addOperation method as needed
$builder = new EventBuilder($target);
// Pass our mocked operations
while (($currAction = array_shift($myOperations)))
{
/*
* We can ignore the result from addOperation here, just keep calling the method
* on the builder variable
*/
$builder->addOperation($currAction);
}
/*
* After we've added all of our operations, we can call compile on the builder instance to
* generate our Action.
*/
$traditionalAction = $builder->compile();
// Run the action
$traditionalResult = $traditionalAction->run();
// Verify that the results from both techniques are identical
assert($fluentResult == $traditionalResult, 'Results from both techniques should be identical');
// Enjoy the fruits of our labor
echo json_encode($traditionalResult, JSON_PRETTY_PRINT).PHP_EOL;
Output:
[
"Repair the Car",
"Clean the Car",
"Drive the Car"
]
Rob Ruchte 感谢您的详细解释,我没有包括的一件事是每个操作本身都有 ->build() 调用,我需要将其移至每个 $builder 以使其工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.