方法链的影响

时间:2010-09-29 12:57:35

标签: php object fluent-interface chaining

我知道在PHP中链接的好处,但我们可以说有以下情况

$Mail = new MailClass("mail")
        ->SetFrom("X")
        ->SetTo("X")
        ->SetSubject("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->Send();

在一次又一次地返回和重复使用对象时是否存在任何问题,例如速度或未遵循最佳做法

等问题

如果您是Fluent-Interface的新手:Martin Fowler on Fluent-Interfaces

,也可以很好地阅读此内容

我完全理解它不会 以这种方式编程,并且可以像这样处理:

$Mail = new MailClass("mail");
$Mail->AddRecipien(
    array(/*.....*/)
);
$Mail->SetFrom("X");
$Mail->SetTo("X");
$Mail->SetSubject("X");
$Mail->Send();

但是我可以说我有一个像这样的对象:

$Order = new Order()
         ->With(22,'TAL')
         ->With(38,'HPK')->Skippable()
         ->With(2,'LGV')
         ->Priority();

注意->With(38,'HPK')->Skippable(),这是此类编程的Pro的完美示例

4 个答案:

答案 0 :(得分:5)

如果你必须验证Something,我认为在AddRecipient方法本身验证更有意义,但性能应该大致相同。而且我不知道使用方法链的任何一般缺点。

答案 1 :(得分:2)

您不能直接从类实例化中链接:

$Mail = new MailClass("mail") 
            ->SetFrom("X")
            ->SetTo("Y");

你必须首先实例化,然后链接实例化的对象:

$Mail = new MailClass("mail") ;
$Mail->SetFrom("X")
     ->SetTo("Y");

如果您在各个setter方法中进行验证(如您所愿),那么您需要确保在遇到验证错误时抛出异常。你不能简单地在错误时返回一个布尔值false,否则链接将尝试针对布尔而不是你的类实例调用下一个方法,你将得到。

  

致命错误:调用成员函数   SetSubject()在非对象中   C:\ xampp \ htdocs \ oChainTest.php在线   23

如果抛出异常,可以将链包装在try ... catch

$Mail = new MailClass("mail");
try {
    $Mail->SetFrom("X")
        ->SetTo("Y")
        ->SetSubject("Z");
} catch (Exception $e) {
    echo $e->getMessage();
}

但作为警告,这将使实例处于部分更新状态,没有回滚(除非您自己编写一个)用于成功验证/执行的方法,并且不会调用异常后面的方法

答案 2 :(得分:1)

编辑:更新了与问题匹配的答案
函数调用比循环慢,即链接,例如addRecipient()方法与调用采用数组然后在循环中处理的数组的addRecipients()方法相比,性能稍微降低。

此外,链接到流畅的API的更复杂的方法可能需要额外记录与最后一个被调用方法相关的数据,以便下一个调用可以继续处理该数据,因为所有方法都返回构建链的同一对象。 我们来看看你的例子:

...
->With(22, 'TAL')
->With(38, 'HPK')->Skippable()
->With(2, 'LGV')
...

这要求您记住Skippable()应用于(38, 'HPK')而不是(22, 'TAL')

你几乎不会注意到性能损失,除非你的代码在一个循环中经常被调用,或者当你有很多并发请求到你的web服务器时它接近它的极限(这是重的情况 - 加载网站)。

另一个方面是方法链接模式强制使用异常来发出错误信号(我不是说这是一件坏事,它只是与经典的“调用和检查函数结果”编码风格不同)。 / p>

通常会有一些函数产生除它们所属对象之外的其他值(例如那些返回对象和访问器状态的值)。 重要的是,API的用户可以确定哪些函数是可链接的,哪些函数不是每次遇到新方法时都必须参考文档(例如,指导所有mutator并且只有mutator支持链接)。 / p>


回答原始问题:

  

[...]我对链接的问题是你无法真正执行额外的验证[...]

<击> 或者,实现在设置所有属性后调用的专用验证方法,并让它返回一组验证失败(可以是纯字符串或对象,例如名为ValidationFailure)。

答案 3 :(得分:0)

这是一把双刃剑。

好的一面?这比重新解决类更清晰,虽然它主要只是语法更改,但它会加快处理速度。最好循环这种链而不是以longform循环每个调用。

坏的一面?当人们第一次习惯它时,这将导致安全问题。要勤勉地净化传入的变种,这样你就不会在那里传递你不应该传递的东西。不要过度复杂化你的课程。

  1. 预先验证您的信息。
  2. 预先授权您的用户。
  3. 我认为将这些方法链接到循环中没有问题。性能方面。