CodeGen
CodeGen copied to clipboard
ChainOperator Expr
How about this:
class:
<?php
namespace CodeGen\Expr;
use CodeGen\Block;
use CodeGen\Renderable;
use CodeGen\Variable;
use LogicException;
class ChainExpr implements Renderable
{
/**
* @var Variable|string
*/
protected $inNewLine;
protected $args;
protected $op = '->';
public function __construct($args, $inNewLine = true)
{
$this->inNewLine = $inNewLine;
if (!is_array($args) || count($args) < 2) {
throw new LogicException('to few arg');
}
$this->args = $args;
}
public function render(array $args = array())
{
$arguments = [];
foreach ($this->args as $arg) {
if ($arg instanceof Renderable) {
$arguments[] = $arg->render($args);
} else {
$arguments[] = $arg;
}
}
if ($this->inNewLine) {
$block = new Block();
$chainBlock = new Block();
$chainBlock->increaseIndentLevel();
foreach ($arguments as $key => $arg) {
if ($key === 0) {
$block->appendLine($arg);
} else {
$chainBlock->appendLine($this->op . $arg);
}
}
$block->appendRenderable($chainBlock);
return $block->render($args);
} else {
return implode($this->op, $arguments);
}
}
public function __toString()
{
return $this->render();
}
}
test:
class ChainExprTest extends CodeGenTestCase
{
public function testChainExprOneLine()
{
$expr = new ChainExpr(
[
new MethodCall(new Variable('$someObject'), 'someMethod'),
new FunctionCall('otherMethod')
],
false
);
$this->assertCodeEquals('$someObject->someMethod()->otherMethod()', $expr);
}
public function testChainExpr()
{
$expr = new ChainExpr([
new MethodCall(new Variable('$someObject'), 'someMethod'),
new FunctionCall('otherMethod')
]);
$this->assertCodeEqualsFile('tests/data/chain_expr.fixture', $expr);
}
public function testChainExprAssign()
{
$expr = new ChainExpr([
new MethodCall(new Variable('$someObject'), 'someMethod'),
new FunctionCall('otherMethod'),
new FunctionCall('anotherMethod')
]);
$assignExpr = new AssignExpr(
new Variable('$someValue'),
$expr
);
$this->assertCodeEqualsFile('tests/data/chain_expr_assign.fixture', $assignExpr);
}
}
fixtures:
$someObject->someMethod()
->otherMethod()
$someValue = $someObject->someMethod()
->otherMethod()
->anotherMethod()
I would prefer adding a ChainedMethodCall for this:
$chain = new ChainedMethodCall($object, [....]);
$chain->otherMethod($arg1, $arg2, $arg3);
$chain->anotherMethod($arg1, $arg2, $arg3);
Use __call to catch the method calls, and generates
$someObject->someMethod(...)->otherMethod(....)