前言:前面0-1完整讲解了TennisGame的重构过程。本节将以一个Insurance的例子继续。本节将使用到一点点无伤大雅的PHPUnit。
注意:PHPUnit的安装过程略过,我使用的是PHP7.1,所以,用到了PHPUnit 7.5.20的安装包。而且,不同版本的PHPUnit的手册差异比较大,在展示的代码或许无法在你的PHP环境中正确运行。这部分的PHPUnit可以忽略。
原始代码
注意:这里的原始代码中的链接是一个无意义的链接,仅为了演示代码重构使用,关键是var_dump返回的那个array
<?php
class Insurance{
public function quote($providers = null)
{
if(!$providers){
$providers = ['bank','insurance-company'];
}else{
$providers = [$providers];
}
$quote = array();
$bank_url = 'https://www.baidu.com/';
for($i = 0;$i<count($providers);++$i){
switch($providers[$i]){
case 'bank':
$prices = file_get_contents($bank_url);
case 'insurance-company':
$curl = curl_init();
curl_setopt_array($curl,array(
CURLOPT_RETURNTRANSFER=>1,
CURLOPT_URL=>'HTTP://123.COM/',
CURLOPT_POST=>1,
CURLOPT_POSTFIELDS=>array(
'month'=>3,
)
));
$prices = json_decode(curl_exec($curl));
curl_close($curl);
}
$quote[$providers[$i]] = $prices;
}
return $quote;
}
}
$insurance = new Insurance();
$quote = $insurance->quote();
var_dump($quote);
?>
可以使用命令行php Insurance.php测试一下。
与之对应的文档test文件是InsutanceTest.test.php
<?php
class InsuranceTest extends PHPUnit_Framework_TestCase{
public function testQuoteNotNull(){
require './Insurance.php';
$insurance = new Insurance();
$quote = $insurance->quote();
$this->assertNotNull($quote['bank']);
$this->assertNotNull($quote['insurance-company']);
}
}
?>
命令行输入phpunit InsuranceTest.test.php测试一下。
Step 0:构造函数,以及providers 的 OOP化
通过这个construct方法,就可以把如下内容取代:
if(!$providers){
$providers = ['bank','insurance-company'];
}else{
$providers = [$providers];
}
<?php
class Insurance{
protected $providers;
public function __construct(Provider $provider = null){
$this->providers = $provider ? [$provider]:[new BankProvider(),new InsuranceCompanyProvider()];
}
public function quote($providers = null)
{
$quote = array();
$bank_url = 'https://www.baidu.com/';
for($i = 0; i<count($this->providers);++$i){
// foreach($this->providers as $provider){
switch($this->providers[$i]){
case 'bank':
$prices = file_get_contents($bank_url);
case 'insurance-company':
$curl = curl_init();
curl_setopt_array($curl,array(
CURLOPT_RETURNTRANSFER=>1,
CURLOPT_URL=>'HTTP://123.COM/',
CURLOPT_POST=>1,
CURLOPT_POSTFIELDS=>array(
'month'=>3,
)
));
$prices = json_decode(curl_exec($curl));
curl_close($curl);
}
$quote[$this->getName()] = $this->provides[$i]->getPrices();
}
return $quote;
}
}
abstract class Provider{
}
class BankProvider extends Provider{
}
class InsuranceCompanyProvider extends Provider{
}
$insurance = new Insurance();
$quote = $insurance->quote();
var_dump($quote);
?>
Step 1: bank类型prices的OOP化,顺便把for改成foreach
<?php
class Insurance{
protected $providers;
public function __construct(Provider $provider = null){
$this->providers = $provider ? [$provider]:[new BankProvider(),new InsuranceCompanyProvider()];
}
public function quote($providers = null)
{
$quote = array();
foreach($this->providers as $privder){
// foreach($this->providers as $provider){
$quote[$privider->getName()] = $provide->getPrices();
}
return $quote;
}
}
abstract class Provider{
abstract function getPrices();
abstract function getName();
}
class BankProvider extends Provider{
public function getName(){
return 'bank';
}
public function getPrices(){
$bank_url = 'https://www.baidu.com/';
$prices = file_get_contents($bank_url);
return $prices;
}
}
class InsuranceCompanyProvider extends Provider{
public function getName(){
return 'insurance-company';
}
public function getPrices(){
$curl = curl_init();
curl_setopt_array($curl,array(
CURLOPT_RETURNTRANSFER=>1,
CURLOPT_URL=>'HTTP://123.COM/',
CURLOPT_POST=>1,
CURLOPT_POSTFIELDS=>array(
'month'=>3,
)
));
$prices = json_decode(curl_exec($curl));
curl_close($curl);
return $prices;
}
}
$insurance = new Insurance();
$quote = $insurance->quote();
var_dump($quote);
?>
可以测试一下
Step 2:进一步把curl解决掉
这个步骤也就是让大家看个思路,由于我没有找到合适的json服务器,所以无法演示器结果。
<?php
class Insurance{
protected $providers;
public function __construct(Provider $provider = null){
$this->providers = $provider ? [$provider]:[new BankProvider(),new InsuranceCompanyProvider()];
}
public function quote($providers = null)
{
$quote = array();
foreach($this->providers as $privder){
// foreach($this->providers as $provider){
$quote[$privider->getName()] = $provide->getPrices();
}
return $quote;
}
}
abstract class Provider{
protected $url = 'https://www.baidu.com/';
abstract function getPrices();
abstract function getName();
}
class BankProvider extends Provider{
public function getName(){
return 'bank';
}
public function getPrices(){
$url = $this->url.'/bank';
$prices = Curl::exec($url);
return $prices;
}
}
class Curl{
public static function exec($url,$opt = []){
$curl = curl_init();
$options = [
CURLOPT_RETURNTRANSFER=>1,
CURLOPT_URL=>$url,
];
if($opt){
$options[CURLOPT_POST] = 1;
$options[CURLOPT_POSTFIELDS] = http_build_query($opt);
}
curl_setopt_array($curl,$options);
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
}
class InsuranceCompanyProvider extends Provider{
public function getName(){
return 'insurance-company';
}
public function getPrices(){
$url = $this->url.'/insurance';
$prices = Curl::exec($url,[
'month'=>3
]);
return $prices;
}
}
$insurance = new Insurance();
$quote = $insurance->quote();
var_dump($quote);
?>
Step 3: 最后一步
<?php
class Insurance{
protected $providers;
protected $curl;
public function __construct(ICurl $curl, Provider $provider = null){
$this->providers = $provider ? [$provider]:[new BankProvider(),new InsuranceCompanyProvider()];
$this->curl = $curl;
}
public function quote($providers = null)
{
$quote = array();
foreach($this->providers as $provider){
$quote[$provider->getName()] = $provide->getPrices($this->curl);
}
return $quote;
}
}
abstract class Provider{
protected $url = 'https://www.baidu.com/';
abstract function getPrices(ICurl $curl);
abstract function getName();
}
class BankProvider extends Provider{
public function getName(){
return 'bank';
}
public function getPrices(ICurl $curl){
$url = $this->url.'/bank';
$prices = $curl->exec($url);
return $prices;
}
}
interface ICurl{
public function exec($url, $opt=[]);
}
class Curl implements ICurl{
public function exec($url,$opt = []){
try{
$curl = curl_init();
$options = [
CURLOPT_RETURNTRANSFER=>1,
CURLOPT_URL=>$url,
];
if($opt){
$options[CURLOPT_POST] = 1;
$options[CURLOPT_POSTFIELDS] = http_build_query($opt);
}
curl_setopt_array($curl,$options);
$result = curl_exec($curl);
curl_close($curl);
return $result;
}catch(Exception $e){
throw new Exception($e);
}
}
}
class InsuranceCompanyProvider extends Provider{
public function getName(){
return 'insurance-company';
}
public function getPrices(ICurl $curl){
$url = $this->url.'/insurance';
$prices = $curl->exec($url,[
'month'=>3
]);
return $prices;
}
}
$curl = new Curl();
$insurance = new Insurance($curl);
$quote = $insurance->quote();
var_dump($quote);
?>
<?php
require './Insurance.php';
class InsuranceTest extends PHPUnit_Framework_TestCase{
public function testQuoteNotNull(){
require './Insurance.php';
$curl = new Curl();
$insurance = new Insurance($curl);
$quote = $insurance->quote();
$this->assertNotNull($quote['bank']);
$this->assertNotNull($quote['insurance-company']);
}
public function testCurlSuccess(){
require './Insurance.php';
$curl = new CurlSuccess();
$insurance = new Insurance($curl);
$quote = $insurance->quote();
$this->assertNotNull($quote['bank']);
$this->assertNotNull($quote['insurance-company']);
}
public function testCurlFail(){
require './Insurance.php';
$curl = new CurlSuccess();
$insurance = new Insurance($curl);
$this->exceptException(Exception::class);
$quote = $insurance->quote();
}
}
class CurlSuccess implements ICurl{
public function exec($url, $opt = [])
{
return ['success'];
}
}
class CurlFail implements ICurl{
public function exec($url, $opt = [])
{
throw new Exception('Failed');
}
}
?>
后记:这篇blog写得太痛苦了,大家讲究看吧。完工