【问题标题】:How to tell if last method in chain?如何判断链中的最后一个方法?
【发布时间】:2013-10-09 02:58:38
【问题描述】:

我已经开始在我的 PHP 应用程序中使用方法链:

$object->do()->something();

特别是查询数据库:

$database->select()->from('mytable');

但是目前我需要调用一个函数来在最后实际执行查询:

$database->select()->from('mytable')->perform();

这很烦人,因为通常每个链都会立即执行。有时不会,但十分之九会。我需要它来处理任何对象,而不仅仅是数据库处理程序。

有没有办法判断我调用的最后一个方法是否是方法本身中的最后一个方法,所以它会 perform() 而无需我告诉它?

如果没有,我可能会尝试使用一些关键字,例如 ->now() 而不是 ->perform()

我有几个想法:

  • 每个方法都有一个参数,如果设置它会让它知道它在最后(也许它可以遍历所有参数以查找是否传递了一个特殊常量?)例如$object->do()->something(now);

【问题讨论】:

  • 请不要链接方法。你违反了CQS
  • @tereško “它显然是作为编程指南而不是良好编码的规则”
  • “它显然是作为编程指南而不是良好编码的规则,例如避免在嵌套循环中使用goto " 另请参阅:martinfowler.com/bliki/CommandQuerySeparation.html

标签: php oop methods


【解决方案1】:

在 Perl 的 DBIX::Class 中,它们在使用数据时触发查询。所以每个查询链都不会返回数据库对象,而是一个环绕数据库表对象的 DBIX::Class 对象。

您可以尝试实施类似的系统。因此,例如以下内容:

$resultSet = $database->select()->from('mytable');

实际上并不返回表,而是返回一个 resultSet 对象。只有当你尝试这样做时:

$resultSet->next();

库是否会真正从数据库中获取数据。

基本上,first()last()all()next() 等所有访问器方法都会获取并缓存数据。如果数据已经被提取并缓存在内存中,那么对 resultSet 对象的访问器方法的进一步调用应该只是读取内存中的哈希值,而不是连接到数据库。


补充细节:

插入没有像 select 这样的复杂子句。所以插入函数不需要是可链接的。因此,对于插入,您可以简单地让 API 执行以下操作:

$database->insert()->into('mytable')->values({
    foo => "hello",
    bar => "world"
});

其中values()方法充当插入函数并触发数据库查询。

可以简单地对行对象进行更新。您可以让 API 执行以下操作:

$row = $database->select()->from('mytable')->first();
$row->foo('goodbye');
$row->update();

或者:

$row->update({
    foo => "goodbye"
});

并让update() 方法触发数据库查询。

【讨论】:

  • 其实我用的时候去取数据听起来还不错。它如何处理更新/插入行、创建表等?
  • 用非数据库类实现这个听起来很棘手。你知道有什么办法吗(否则我自己去试试)?
  • 据我所知,插入行和更新数据库只会导致它删除其内部哈希。尝试读取数据将导致进行另一个数据库查询。我相信这是可以配置的,默认情况下从数据库重新加载只是为了安全。
  • 核心概念是数据在内存中,但如果数据缓存为空(perl 中的undef),则从文件/网络中读取数据。这通常也通过模板库(例如 Template Toolkit)来实现。唯一的区别是数据对象还存储创建它的构造查询,以便可以在获取实际数据之前修改查询,或者如果需要刷新数据则重复查询。
  • 您可以使用这种技术轻松实现文件读取器,该技术将查询参数映射到磁盘上的文件,然后仅在您调用其next_line() 方法时读取文件。或者另一个想法,一个具有相同想法的 css 或 js 汇总实用程序,允许您继续向对象添加 css 或 js 文件,但仅在调用其 print() 方法时读取磁盘上的文件。
【解决方案2】:

使用运算符重载extension,您可以指定一元运算符之一来提示执行

例子:

~$db->select()->from()->where();

如果您想避免安装扩展程序,我可以提出的一个建议是在您最近的链调用中使用某种转义字符来提示执行。您应该从最终查询中省略它以避免语法错误。

例子:

$db->select()->from()->where("id = 1 ~"); //~ character implies automatic execution

【讨论】:

  • 我对重载运算符和使用扩展感到不安。不过感谢您的回答。
【解决方案3】:

有没有办法判断我调用的最后一个方法是否是方法本身中的最后一个

不,我相信没有这样的事情。那是因为“链式调用”与“一个接一个的调用”没有区别。这只是“call => return object => call => return object ...”链的一种语法糖。

I have a few idea(s):

 - each method has a parameter that if set will let it know it's at the end (maybe it can 
   loop through all parameters to find if a special constant was passed?) eg
   $object->do()->something(now);

您可以实现overloading __call() method 建议的想法的效果。这样你可以很好地抽象你的参数检查逻辑。

但请注意,这种行为在架构方面并不是很明显,您可能应该考虑类似 PDO 的方法,即使用像 perform()do() 这样的“最终化”方法,我认为您已经有了.

【讨论】:

  • 重载__call() 方法是个好主意。你是对的,我已经使用了 finalize 方法(目前是perform())。
猜你喜欢
  • 2015-10-15
  • 1970-01-01
  • 2014-08-16
  • 1970-01-01
  • 2011-05-03
  • 2013-07-06
  • 2021-02-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多