方法链接的影响

发布于 2024-09-25 06:03:02 字数 1131 浏览 10 评论 0原文

我知道 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 谈 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 示例

I know the benefits of chaining within PHP but lets say we have this following situation

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

Are there any issues with returning and reusing the object over and over again, issues such as speed or failure to follow best Practises

Also a good read on this if your new to Fluent-Interface's: Martin Fowler on Fluent-Interfaces

I Fully understand that it doesn't have to be programmed this way, and can be handled like so:

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

but lets say I have an object like so:

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

Note the ->With(38,'HPK')->Skippable(), This is perfect example of a Pro for this type of programming

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萌化 2024-10-02 06:03:02

如果您必须验证某些内容,我认为在 AddRecipient 方法本身中验证它更有意义,但性能应该大致相同。我不知道使用方法链接有任何一般缺点。

If you have to validate Something, i think it makes more sense to validate it in the AddRecipient Method itself, but the Performance should be about the same. And I'm not aware of any general disadvantages of using method chaining.

许仙没带伞 2024-10-02 06:03:02

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

$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();
}

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

You can't chain directly from the class instantiation:

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

you have to instantiate first, then chain against the instantiated object:

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

If you validate within the individual setter methods (as you should) then you need to ensure that you throw exceptions when a validation error is encountered. You can't simply return a boolean false on error, otherwise the chaining will try to call the next method against a boolean rather than you class instance and you'll get.

Fatal error: Call to a member function
SetSubject() on a non-object in
C:\xampp\htdocs\oChainTest.php on line
23

if you throw exceptions, you can wrap the chain within try... catch

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

but as a warning, this will leave the instance in a partially updated state, there's no rollback (unless you write one yourself) for the methods that did validate/execute successfully, and the methods following the exception won't be called.

乙白 2024-10-02 06:03:02

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

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

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

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

不过,您几乎不会注意到性能损失,除非您的代码将在循环中非常频繁地调用,或者您的 Web 服务器有如此多的并发请求,以致它接近其极限(对于重负载网站来说就是这种情况) 。

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

然而,通常会有一些函数产生除它们所属的对象之外的其他值(例如,那些返回对象和访问器的状态的函数)。
重要的是,API 的用户可以确定哪些函数是可链接的,哪些函数是不可链接的,而无需每次遇到新方法时都参考文档(例如,说明所有变元且仅变元支持链接的指南)。


回答原来的问题:

[...]我在链接方面遇到的问题是您无法真正执行额外的验证[...]


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

EDIT: Updated answer to match the question
Function calls are slower than loops, i.e. chaining for example the addRecipient() method degrades performance a tiny bit compared to calling an addRecipients() method that takes an array that is then processed in a loop.

Furthermore, more sophisticated method chaining up to fluent APIs may require additional book-keeping of data related to the last called method so that the next call can continue working on that data because all methods return the same object on which chain is built.
Let's take a look at your example:

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

This requires you to remember that Skippable() is to be applied to (38, 'HPK') rather than (22, 'TAL').

You will hardly notice a performance loss though unless your code is going to be called very frequently in a loop or when you have so many concurrent requests to your web server such that it approaches its limits (which is the case for heavy-load websites).

Another aspect is that the method chaining pattern enforces the use of exceptions to signal errors (which I'm not saying is a bad thing, it just differs from the classical "call and check function result" style of coding).

There will usually be functions however which yield other values than the object to which they belong (e.g. those returning the status of the object and accessors).
It is important that the user of your API can determine which functions are chainable and which are not without having to refer to the documentation each time he encounters a new method (e.g. a guideline that says that all mutators and only mutators support chaining).


Answer to the original question:

[...] The issues i have with chaining is the fact that you cant really perform extra validation [...]


Alternatively, implement a dedicated validation method that you call after setting all properties and have it return you an array of validation failures (which can be plain strings or objects, e.g. named ValidationFailure).

妥活 2024-10-02 06:03:02

这是一把双刃剑。

好的一面?这比重新寻址类更干净,虽然它主要只是语法更改,但它会稍微加快处理速度。循环这种链比循环长格式的每个调用更好。

坏的一面?当人们第一次习惯它时,这会导致安全问题。勤奋地净化传入的变量,这样你就不会在其中传递一些不应该传递的东西。不要让你的课程过于复杂。

  1. 预先验证您的信息。
  2. 预先授权您的用户。

从性能角度来看,我认为将这些方法链接到循环中没有问题。

This is a double edged sword.

The good side? This is cleaner than re-addressing the class and although it is mostly just a syntax change it is going to speed up the processing a little. It would be preferable to loop this kind of a chain than to loop each call in longform.

The bad side? This will cause security issues when people first get used to it. Be diligent in your purification of incoming vars on this so you don't pass something in there you shouldn't. Don't over-complicate your classes.

  1. Pre-validate your information.
  2. Pre-authorize your users.

I see no problem with chaining these methods into a loop, performancewise.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文