簡體   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