繁体   English   中英

开发可维护的RPC系统

[英]developing a maintainable RPC system

我正在开发一个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方法。

我最初的想法是将docblock注释@export添加到我想要公开的方法/类中。 当我决定公开setTitle方法时,我只是添加注释而不是新方法。

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

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

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

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

另一个问题是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),您应该只公开您的服务层,然后依次访问它们的实体及其各自的方法。

“您的Book类是域模型,您现在应该创建服务层”

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

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中,你可以制作一些形式的魔术方法

集合{对象} {属性}。

您可以通过magic __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]并处理它。 当涉及到公开函数时,你将它们暴露在文档中,只要它们是从那时起的公共函数等,它们都是可访问的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM