舉個例子,斷言直接裸露的寫在控制器中
控制器的方法
<?php
use App\Models\Order;
class OrderController extends Controller
{
public function applyRefund(Order $order, ApplyRefundRequest $request) {
// 1.斷言 - 判斷是否未支付
if (! $order->paid_at) {
throw new InvalidRequestException('該訂單未支付,不可退款');
}
// 2.斷言 - 判斷訂單是否已退款
if ($order->refund_status !== Order::REFUND_STATUS_PENDING) {
throw new InvalidRequestException('該訂單已經申請過退款,請勿重複申請');
}
...
}
}
這樣寫不是不可以,也是正確的,但是存在三面問題:
- 斷言有點長,看起來不夠優雅,控制器的程式碼應簡約一點。
- 斷言不具有語義化,閱讀起來不能快速理解其含義。
- 後期程式碼需要批次修改,麻煩且容易出錯。
針對以上問題我要做是以下兩點:
- 長的斷言修改為方法,寫入到模型中,控制器直接呼叫模型方法即可。(程式碼看起來簡約且後期維護只需修改模型方法)
- 方法名使用快速可讀,可理解其中含義的名稱。
最佳化後的樣子
模型中的方法:
<?php
namespace App\Models;
class Order extends Model
{
// 退訂狀態
const REFUND_STATUS_PENDING = 'pending';
// 是否未付款
public function isUnpaid() :bool
{
return ! ($this->paid_at);
}
// 是否訂單已退款
public function isRefunded() :bool
{
return $this->refund_status !== self::REFUND_STATUS_PENDING;
}
}
控制器中的呼叫:
<?php
use App\Models\Order;
class OrderController extends Controller
{
public function applyRefund(Order $order, ApplyRefundRequest $request) {
// 1.斷言 - 判斷是否未支付
if ($order->isUnpaid()) {
throw new InvalidRequestException('該訂單未支付,不可退款');
}
// 2.斷言 - 判斷訂單是否已退款
if ($order->isRefunded()) {
throw new InvalidRequestException('該訂單已經申請退款,請勿重複申請');
}
...
}
}
完了麼?並沒有,我們們繼續最佳化!!
模型中的方法:
<?php
namespace App\Models;
class Order extends Model
{
// 退訂狀態
const REFUND_STATUS_PENDING = 'pending';
// 是否未付款
public function isUnpaid() :bool
{
return ! ($this->paid_at);
}
// 直接丟擲異常 - paid_at 未支付時值為null
public function isUnpaidNotSupported() :bool
{
return ! $this->isUnpaid() ?: throw new InvalidRequestException('該訂單未支付,不可退款');
}
// 是否訂單已退款
public function isRefunded() :bool
{
return $this->refund_status !== self::REFUND_STATUS_PENDING;
}
// 直接丟擲異常
public function isRefundedNotSupported() :bool
{
return ! $this->isRefunded() ?: throw new InvalidRequestException('該訂單已經申請退款,請勿重複申請');;
}
}
控制器中的呼叫:
<?php
use App\Models\Order;
class OrderController extends Controller
{
public function applyRefund(Order $order, ApplyRefundRequest $request) {
// 1.斷言 - 判斷是否未支付
$order->isUnpaidNotSupported()
// 2.斷言 - 判斷訂單是否已退款
$order->isRefundedNotSupported()
...
}
}
如此這樣,控制器的判斷看起來不那麼蹩腳,讀起來也很通順,後期程式碼維護直接修改模型方法,且屬性也可調整,挺好!以後都按照這種方式寫具有可讀可維護性的程式碼!賞心也悅目,哈哈!
還能再最佳化麼?
- 我想還能最佳化,直接控制器無需斷言。
- 將斷言放入中介軟體中。
- 將斷言放入請求類中,都可以,就看你要最佳化到那種程度了。
本作品採用《CC 協議》,轉載必須註明作者和本文連結