O encadeamento de métodos é um recurso interessante e útil especialmente para API sequencial procedural.
O que torna possÃvel o encadeamento é retornar a cada chamada de método a instância do objeto chamado.
A classe Chainable é um invólucro simples para fazer chamadas de proxy para métodos de classe e retornar a referência de instância que permite o encadeamento de métodos.
Por exemplo, considere a classe Test, que possui três métodos:
class Test {
function foo(){ echo "FOO"; }
function baz(){ return "BAZ"; }
function bar(){ echo "BAR"; }
}
e este exemplo usa:
$test = new Test();
$test->foo();
$value = $test->baz();
$test->bar();
echo "n",'The value was : ',$value;
/* Output:
FOOBAR
The value was : BAZ
*/
Considere agora a oportunidade de métodos de cadeia, é isso que queremos alcançar:
$test->foo()->bar();
Para fazer isso, sem modificar a classe Test, devemos envolvê-la em outra classe de proxy e redirecionar todas as chamadas para a instância embalada.
class Chainable {
private $instance = null;
public function __construct(){
$pars = func_get_args();
$this->instance = is_object($obj=array_shift($pars))?$obj:new $obj($pars);
}
public function __call($name,$pars){
call_user_func_array([$this->instance,$name],$pars);
return $this;
}
}
Agora podemos encerrar o teste com chamadas de métodos Chainable e chain:
$test = new Chainable('Test');
$test->foo()->baz()->bar();
/* Output:
FOOBAR
*/
Agradável! Mas espere … baz () retorna um valor … mas nosso proxy está perdendo-o.
Podemos corrigir a captura de valores de método retornados em um cache interno e fornecer um método encadeado para recuperá-los:
private $_returns = [];
// Retrieve the returned value from last
// chained method
public function _get_return(&$var){
$var = count($this->_returns)?
array_pop($this->_returns):null;
return $this;
}
// Clear the returned value cache
public function _reset(){
$this->_returns = [];
return $this;
}
// Redefine call proxy for saving returned values
public function __call($name,$pars){
($r=call_user_func_array([$this->instance,$name],$pars))?$this->_returns[]=$r:null;
return $this;
}
Agora, podemos recuperar o valor salvo durante a cadeia de chamadas:
$test = new Chainable('Test');
$test
->foo()
->baz()->_get_return($the_value)
->bar();
echo "nn",'The value was : ',$the_value;
/* Output:
FOOBAR
The value was : BAZ
*/
E terminamos.
Você pode encontrar a aula completa e este exemplo aqui:
https://gist.github.com/lastguest/4732993