<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ## 一個需求 做的某項目有一個“轉賬”的功能,但是轉賬的類型有很多種,對應每種轉賬需要的參數也不同,舉個例子一種轉賬是由系統轉賬給用戶,那么就只有接收方和金額兩個參數,另一種轉賬是用戶之間的轉賬且支持留言,那么就有發送方接收方金額和留言四個參數。當然最簡單的思路就是采用四個參數,對于第一種轉賬將不用的兩個參數留空,這種方法的問題在于,考慮到未來可能增加的新的轉賬類型,可能會引入新的參數,那么代碼很可能需要推倒重來,有沒有更優雅的解決方式呢? ## 一個例子 其實Laravel里就有實現類似需求的例子,那就是查詢構造器(Query Builder),它的一個使用的例子如下: $users = DB::table('users') ->select(DB::raw('count(*) as user_count, status')) ->where('status', '<>', 1) ->groupBy('status') ->get(); 這個方法和我們的需求就很像了,對于查詢這一功能,傳入哪些參數是未知的,例如某次具體的查詢,可能需要調用groupBy也可能調用orderBy,也可能兩者需要同時調用或者都不調用。一個思路就是針對每一個參數都寫一個方法,需要時則調用,不需要時則不調用。 ## 解決方案 整體的解決思路是寫兩個類,一個叫Transfer,一個叫Builder,每個參數對應的方法寫在Builder里,由Transfer去調用Builder構造我們需要的轉賬類型,完成相關操作。這樣當需求更新時(要增加新的參數時),只要在Builder里添加相應的方法即可,而不用改動現有代碼。下面先貼一下對應的代碼再做詳細解釋。 Transfer類代碼: class Transfer { public function __call($method, $parameters) { $builder = new Builder(); return call_user_func_array([$builder, $method], $parameters); } public static function __callStatic($method, $parameters) { $instance = new static; return call_user_func_array([$instance, $method], $parameters); } } Builder類實際上只涉及到具體的功能實現,就貼部分代碼意思意思看看就行: class Builder { protected $from = 0; // 0 represents system protected $to = 0; protected $amount = 0; protected $comments = ''; protected $related = []; public function from($user) { if ($user instanceof User) { $this->from = $user->getAuthIdentifier(); } elseif (is_int($user)) { $this->from = $user; } else { throw new InvalidArgumentException(sprintf('%s excepts $user parameter to be \App\User or integer, %s given.', __METHOD__, gettype($user))); } return $this; } public function to($user){...} public function amount(int $amount){...} public function comments($comments){...} public function related(int $type, int $id, $extra = null){...} public function transfer(){...} } 具體調用Transfer功能的代碼: Transfer::from($sender)->to($receiver)->amount($amount)->comments($comments)->related($related_type, $related_id, $related_extra)->transfer(); ## 代碼解釋 下面我們來走一遍調用Transfer的流程來看看。首先調用了Transfer類中的靜態方法from,然而Transfer中并不存在這個靜態方法,則會自動調用__callStatic()這個魔術方法。這個方法首先實例化了一個static對象。注意這里的static是一個類名,new出來的$instance是屬于static這個類的一個實例化對象,有點拗口... 然后返回時調用了call_user_func_array這個方法,這個方法具體可以參考php的手冊,實際上它完成了類似$instance->method($parameters)這樣的操作,放到我們當前的情境下實際執行了$transfer_instance->from($user)這樣的操作。 然后發覺Transfer中并不存在這個動態方法,于是又會自動調用__call()這個魔術方法。這個方法首先創建了一個Builder類的實例,之后調用call_user_func_array這個方法,實際上相當于執行了$builder->from($user)方法,然后終于得Builder類里找到了這個from()方法,注意它的返回值是$this。(補充閱讀:self vs. this in PHP) 然后當前這個Builder這個對象繼續調用to方法,發覺又不存在又去調用__call()這個魔術方法,之后的過程同上,反復調用Builder中的方法把所有需要的參數都處理過以后最后調用了transfer()方法最終完成轉賬操作。 ## 需要的儲備知識 1. PHP魔術方法__call()和__callStatic() 2. call_user_func_array() 3. PHP面向對象基礎知識
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看