說明
本文主要結合程式碼說明如何去在寫程式碼時做到 一個類只做一件事
。
需求
實現一個 cURL
類,針對不同平臺的 API
進行操作,並最終返回 array
給方法的呼叫方。
思路
分析需求設計到的功能點:
cURL
操作類- 不同平臺的驗證規則可能不一樣,所以每一個平臺都應該對應一個類
cURL
請求一般返回的是字串,需要將結果轉化為array
實現
-
定義好
CurlInterfaceDriver
類的Interface
規範。主要定義三個常用方法
namespace App\Curl\bin; interface CurlInterfaceDriver { public function get($url, $options = []); public function post($url, $options = []); public function request($method, $url, $options = []); }
-
實現抽象類
AbstractHttpCurlDriver
namespace App\Curl\bin; use GuzzleHttp\Client; abstract class AbstractHttpCurlDriver implements CurlInterfaceDriver { /** * @var null|Client */ protected $client = null; protected $response = null; public function __construct(Client $client = null) { if (is_null($client)) { $client = new Client(); } $this->setClient($client); } /** * @param $url * @param array $options * @return string * @date 2019/01/25 * @author ycz * @throws \GuzzleHttp\Exception\GuzzleException */ public function get($url, $options = []) { $response = $this->getClient()->request('GET', $url, $options)->getBody()->getContents(); $this->setResponse($response); return $response; } /** * @param $url * @param array $options * @return string * @date 2019/01/25 * @author ycz * @throws \GuzzleHttp\Exception\GuzzleException */ public function post($url, $options = []) { $response = $this->getClient()->request('POST', $url, $options)->getBody()->getContents(); $this->setResponse($response); return $response; } /** * @param $method * @param $url * @param array $options * @return string * @date 2019/01/25 * @author ycz * @throws \GuzzleHttp\Exception\GuzzleException */ public function request($method, $url, $options = []) { $response = $this->getClient()->request($method, $url, $options)->getBody()->getContents(); $this->setResponse($response); return $response; } /** * @return null|Client */ private function getClient() { return $this->client; } /** * @param Client $client */ private function setClient(Client $client) { $this->client = $client; } /** * @return null|string */ public function getResponse() { return $this->response; } /** * @param null|string $response */ private function setResponse($response) { $this->response = $response; } }
-
每個平臺返回資料格式可能不一樣,所以抽象類中只將結果字串返回,針對不同返回資料格式,我們可以建立不同的
Driver
繼承AbstractHttpCurlDriver
針對
JSON
返回結果的類。namespace App\Curl\bin; class JsonHttpCurlDriver extends AbstractHttpCurlDriver { }
針對
XML
返回結果的類。namespace App\Curl\bin; class XMLHttpCurlDriver extends AbstractHttpCurlDriver { }
因為
JSON
和XML
兩個驅動的只有返回結果不一樣,其他內容基本一樣,所以不用在自己類裡面改寫抽象類裡面的東西。 -
實現將
response
轉換為array
的類根據使用的
driver
自動轉換結果。namespace App\Curl\bin; use App\Exceptions\ResponseNotJsonException; use App\Exceptions\ResponseNotXMLException; use SimpleXMLElement; class ApiData2ArrayFactory { public static function make(CurlInterfaceDriver $curl) { if ($curl instanceof JsonHttpCurlDriver) { return static::json2Array($curl->getResponse()); } if ($curl instanceof XMLHttpCurlDriver) { return static::xml2Array($curl->getResponse()); } } /** * json 轉陣列 * * @param $json * @return array * @date 2019/01/25 * @author ycz * @throws ResponseNotJsonException */ private static function json2Array($json) { try { $data = \GuzzleHttp\json_decode($json, true); } catch (\InvalidArgumentException $e) { throw new ResponseNotJsonException(); } return $data; } /** * @param $xml * @return array * @date 2019/01/25 * @author ycz * @throws ResponseNotXMLException */ private static function xml2Array($xml) { if (!static::isXml($xml)) { throw new ResponseNotXMLException(); } function _XML2Array(SimpleXMLElement $parent) { $array = array(); foreach ($parent as $name => $element) { ($node = &$array[$name]) && (1 === count($node) ? $node = array($node) : 1) && $node = &$node[]; $node = $element->count() ? _XML2Array($element) : trim($element); } return $array; } $xml = new SimpleXMLElement($xml); $data = _XML2Array($xml); return $data; } /** * @param $xml * @return int * @date 2019/01/25 * @author ycz */ private static function isXml($xml) { return xml_parse(xml_parser_create(), $xml, true); } }
-
實現對外呼叫的
cURL
類namespace App\Curl\bin; /** * Class Curl * * @package App\Curl\bin * @method get * @method post * @method request * @see AbstractHttpCurlDriver */ class Curl { private $curlDriver = null; public function __construct(CurlInterfaceDriver $curl) { $this->curlDriver = $curl; } public function __call($name, $arguments) { $this->curlDriver->$name(...$arguments); return ApiData2ArrayFactory::make($this->curlDriver); } }
-
實現單個平臺的
cURL
類,以亞馬孫為例,我們建立一個AmazonCurl
namespace App\Curl\Amazon; use App\Curl\BaseCurl; use App\Curl\bin\Curl; use App\Curl\bin\JsonHttpCurlDriver; class AmazonCurl extends BaseCurl { public function __construct() { $this->curl = new Curl(new JsonHttpCurlDriver());//假設亞馬遜返回的是 json 資料 } public function getProductList() { return $this->curl->get('http://amazon.com/get-product-list',[]); } }
-
外部呼叫
$amazonCurl = new AmazonCurl(); return $amazonCurl->getProductList();
-
說明
如果哪天亞馬遜的介面返回變成了
XML
資料,我們只用將AmazonCurl
建構函式中的JsonHttpCurlDriver
替換為XMLHttpCurlDriver
即可。後續如果新增了其他格式的資料返回,支援新資料只用實現兩個東西:1. 繼承於
AbstractHttpCurlDriver
的驅動類。2. 在ApiData2ArrayFactory
實現改格式轉array
的方法。
本作品採用《CC 協議》,轉載必須註明作者和本文連結