2014-01-06 41 views
0

我在php中有一个类可以与链式方法一起工作,但问题是我想按某种顺序链接这些方法。Cahining pattern

class Chain { 
    public function foo() { 
    return $this; 
    } 
    public function bar() { 
    return $this; 
    } 
    public function some() { 
    return $this; 
    } 
} 

所以,如果我使用这个类的话,我可以链接这个方法在9种不同的方式(3个元素的所有可能的组合)

但是,如果我决定什么发生,该方法some必须始终在foobar之后链接,而不是以其他方式链接?

$chain = new Chain(); 
$chain->foo->bar(); //works; i.e: the method some is optional 
$chain->foo()->bar()->some(); //works 
$chain->bar()->foo()->some(); //works 
$chain->some()->bar()->foo(); //throws an exception 

我认为我可以做到这一点设置布尔值,是这样的:该方法foobar被调用时,然后我将该值设置为一些变种来true,当开发者调用some功能,如果该变量为false,则引发异常,否则允许继续。

但我需要更优雅的东西,比如图案或内置解决方案。

还有另一种方法可以做到吗?

+0

如果你不想叫'栏()''如果foo的()'不叫之前,除了检查返回值之外没有别的办法。你可以做一个代理方法(包装器),它可以完成所有的工作,只需在'bar()'中指定参数'foo()', –

回答

1

非常粗略的例子,我想象仍会有一些代码行中的每个方法

<?php 
class Chain { 

    private $_register = array(); 

    public function foo() { 
    $this->register(__METHOD__); 
    return $this; 
    } 
    public function bar() { 
    $this->register(__METHOD__); 
    return $this; 
    } 
    public function some() {; 
    $this->verify('foo'); // foo() should be called before some(); 
    $this->register(__METHOD__); 
    echo 'it\'s ok'; 
    return $this; 
    } 
    public function verify($method) { 
     if(array_key_exists($method, $this->_register) && $this->_register[$method] == true) { 
      return true; 
     } 
     else { 
      throw new Exception('Some exception'); 
     } 
    } 
    public function register($method) { 
     $method = str_replace(__CLASS__.'::', '', $method); 
     $this->_register[$method] = true; 
    } 
} 

我们做什么在这里 - 我们有一个register()verify()方法。 (也可以是助手,但是对于当前的目的我加入他们的类。

之前,它的返回值的寄存器本身每个方法都应该有。拨打国际长途foo()$this->register(__METHOD__)将私人数组中添加'foo' => true。 的verify()方法检查foo是否作为数组键存在,如果其值为true。如果是 - 脚本将继续,否则 - 抛出异常。

在这种情况下:

$chain = new Chain(); 
$chain->bar()->some()->foo(); //throws an exception 

Fatal error: Uncaught exception 'Exception' with message 'Some exception' in ...

$chain = new Chain(); 
$chain->foo()->some()->foo(); // ok 

it's ok

这里的问题是,我们建立了 “公约”。您需要将__METHOD__传递给注册函数,因此在替换类名后,它只会在数组中添加方法名称。所以后来,在你需要验证,如果一个或多个功能在此之前调用的函数,你需要使用方法名作为字符串即$this->verify('foo');

Ofcourse,你可以不剥离,并与strpos()测试或添加扮演不同的场景()之后的方法名称更容易识别,如果您正在验证方法或其他人。

但至少这将节省您进行每种方法,不同的变量,以填补即

function foo() { 
    $this->_foo = true; 
    return $this; 
} 
function bar() { 
    $this->_bar = true; 
    return $this; 
} 
1

强迫呼叫者坚持一定的呼叫顺序,就像自己终止一样毫无用处。假设你真正感兴趣的是当你调用some()时确保对象的状态是有效的,如果不是则抛出异常。在这种情况下,是的,您会检查对象状态的某些指标,并在该状态不符合可能调用some()的要求时抛出异常。作为一个具体的例子:

$api = new SomeAPI; 
$api->setUserID($id); 
$api->setSecretKey($secret); 
$api->call('something'); 

这里call()会检查用户ID和访问密钥已定,否则就不能完成其工作。这些调用是否被链接是无关紧要的,只是一个句法细节。

或者,你可以返回从方法的其他(子)的特定对象,其身体使其无法调用它们的某些方法,如果某些条件没有得到满足类:

public function bar() { 
    if ($this->foo) { 
     return new SubFoo($this->foo); 
    } else { 
     return new SubBar; 
    } 
} 

这可能是尽管过于复杂。