我正在开发一个 Web 应用程序,该应用程序将广泛使用 AJAX 技术进行客户端/服务器通信……特别是 JSON-RPC。Zend Framework 正在服务器端使用,它提供了一个我想使用的很好的 JSON-RPC 服务器。

我的目标是构建一个可维护的系统,公开 大的 服务器端功能的子集到客户端(javascript),没有不必要的代码重复。我看过很多关于如何使用 ZF 的 JSON-RPC 服务器的博客文章和教程(请参阅 这里这里),但它们似乎都旨在公开一个小型的、可公开使用的 API。代码重复很常见,例如一篇博客文章公开了以下方法:

public static function setTitle($bookId, $title) {
    $book = new Nickel_Model_Book($bookId);
    $book->setTitle($title);
    $book->update();
    return true;
}

我不喜欢有两个这样的事实 setTitle 方法。如果一个方法签名发生变化,另一个就必须保持同步……如果您的 API 很广泛,这似乎是可维护性的噩梦。在我看来应该有一个 Book 类,有一个 setTitle 方法。

我最初的想法是添加一个文档块注释 @export 我想要公开的方法/类。当我决定揭露 setTitle 方法,我只是添加注释而不是新方法。

我看到的一个潜在问题涉及对象持久性。服务器端,这是有意义的 setTitle 设置对象的标题属性...但不要将其保留在数据库中,直到 update() 叫做。客户端,调用 setTitle 应该立即影响数据库。一种可能的解决方案是修改所有访问器,使它们采用可选的第二个参数,表示修改应立即更新数据库:

function setTitle($title, $persist = false) {
    $this->title = $title;

    if ($persist) $this->update();
}

某种代理类可以确保 $persist 为所有客户端 RPC 调用设置标志。

另一个问题是 PHP 对象的序列化。服务器端,采用 OO 风格是有意义的 $book->setTitle("foo") 调用,但是客户端 book.setTitle(1234, "foo") 由于缺乏状态,这是有道理的(其中 1234 是书的 ID)。我的解决方案是让上述代理类负责以某种方式转向 book.setTitle(1234, "foo") 进入:

$book = new Book();
$book->load(1234);
return $book->setTitle($title);

我觉得这个问题之前一定已经被解决或讨论过......但我在网上找不到很多资源。这看起来是一个明智的解决方案吗?

有帮助吗?

解决方案

你正在寻找的东西叫做 服务层.

它们的实体应该是纯粹的数据容器(除非您使用 Active Record),您应该只公开您的服务层,而这又会访问它们的实体及其各自的方法。

"Your Book class is a Domain Model, you should now create your Service Layer"

您的服务等级将是这样的:

class BookService extends Service {

    //...

    public function changeBookTitle( $title, Book $book )
    {
        //verify if the $title is correct and valid
        $book->setTitle( $title );
        $this->methodToGetThePersistenceManager()->save( $book );

        //fire events, create a result object, etc...
    }
}

其他提示

我思考了你的问题几分钟。如果你想尝试,并且它是用 PHP 编写的,你可以制作一些以下形式的神奇方法

设置{对象}的{属性}。

您可以通过神奇的 __call 方法来做到这一点。

这样您就不必显式定义方法,但属性仍然会被设置。

这个神奇的方法将识别它必须实例化哪种类型的对象以及要在其上设置哪个属性然后持久化。

不过,您必须找到某种方法来区分远程调用和本地调用,以便在进行本地库调用并且确实坚持远程调用时不会错误地坚持下去。

我觉得我以某种方式误解了你的问题,但我尝试过。

出色地,

您想要做的事情在纸面上听起来非常好,并且您希望代码是可维护的,并且根据您的实际系统,您所要求的甚至可能有些安全,但是它接近危险且容易出错。

无论如何,您可能必须自己完成大部分工作,或者只是在所有方法调用中插入某种拦截器,这是一个简单的示例:

class Book {
  public $title = '';
  public $id = 0;
  public function setTitle($string) {
    $this->title = $string;
    echo "title called with $string\n";
  }
  public function twoArgs($arg1,$arg2) {
    echo "Multi-call: $arg1,$arg2\n";
  }
}
class Api {
  public function parse($json) {
    $jsonobj = json_decode($json,true);
    foreach ($jsonobj as $key=>$value) {
      $class_name = $key;
      $obj = new $class_name();
      foreach ($value as $vkey=>$vvalue) {
        if (method_exists($obj,$vkey)) {
          call_user_func_array(array($obj,$vkey),$vvalue);
        } else if (isset($obj->$vkey)) {
          echo "Setting $vkey\n";
          $obj->$vkey = $vvalue;
        }
      }
    }
  }
}

$json = json_encode(array('Book' => array('id' => 1234, 'setTitle' => array('The new title'))));
$api = new Api();
$api->parse($json);
$json = json_encode(array('Book' => array('id' => 1234, 'twoArgs' => array('arg1 :) ', 'arg2 :]'))));
$api->parse($json);

显然,您需要添加逻辑来处理持久标记,并加载或允许它们传入构造函数:[args] 并处理它。ETC。当涉及到公开函数时,您可以在文档中公开它们,只要从那时起它们是公共函数,它们就都可以访问。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top