最近在開發某一個項目功能,這也是先前同事踩到的坑,這次換我在踩一次,順便記錄一下,主要發生情境是,在執行GET參數,定義一個isDownlineSearch 布林判斷時,當前端傳入true or false,在執行以下程式碼判斷時會失敗,他無法正確判斷此值,$isDownlineSearch取得的value不管是true or false,皆認為ture,除非你輸入1 or 0
範例程式如下
$isDownlineSearch = $request->query->get('isDownlineSearch', true);
$whereColumn = 'uid';
if($isDownlineSearch){
$whereColumn = 'upperId';
}
當我傳入isDownlineSearch = false
時,正常不應該進入這個判斷式,我們試著將程式碼打印出來 var_dump($isDownlineSearch)
看段程式碼結果,可以看到傳入值為字串string 的 false
,而在PHP 中,當你使用 if
條件語句來測試一個字串(string)時,如果字串不為空,則 if
條件將被視為 true
。
根據PHP執行結果,因為傳入是字串,故程式碼永遠判斷為 true
進而將whereColumn設定為'upperId',非我預期的結果'uid'。
後來查了類似情況,Laravel 對於boolean驗證,不接受true or false
,但接受1 or 0
,而在你編寫測試時,當你設定傳入參數$isDownlineSearch = true,跑測試結果時,$isDownlineSearch 會變成 1 ,所以預期測試情況下都會是測試正常結果,但上線時就會出問題XDDDD
即使你將程式碼改為下列的判斷式,但測試執行的$isDownlineSearch 會變成 1,這段程式碼又會不成立,因為嚴格比較運算符 ===
表示不僅要比較值,還要比較數據類型是否相同,所以if (1 === true)
的結果是 false
,因為整數 1
和布林值 true
的數據類型不相同。
$whereColumn = 'uid';
if($isDownlineSearch === true ){
$whereColumn = 'upperId';
}
那你一定會想說那我改成非嚴格比較運算符 ==
,這樣就行了吧,但這段解決了測試,卻沒解決先前的if(string)
總是等於true的情況
$whereColumn = 'uid';
if($isDownlineSearch == true ){
$whereColumn = 'upperId';
}
查看 laravel 類似案例後,解法可以使用PHP filter_var 這個方法
filter_var($value, FILTER_VALIDATE_BOOLEAN);
當你使用這個過濾方式,將取得字串的 true or false
轉換為 boolean值
$isDownlineSearch = $request->query->get('isDownlineSearch', true);
$isDownlineSearch = filter_var($isDownlineSearch, FILTER_VALIDATE_BOOLEAN);
我們把他 var_dump($isDownlineSearch);
出來看一下,可以看到傳入值已經被轉為布林值,底下的if判斷也能正常執行了
Boolean Rule 通用規則
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Boolean implements Rule
{
/** * laravel 內建 Boolean validation 不接受 'true', 'false' * 參考 https://github.com/laravel/ideas/issues/514 * * @param string $attribute * @param mixed $value * @return bool */
public function passes($attribute, $value)
{
if (is_bool($value)) {
return true;
}
if (in_array($value, ['true', 'false', '1', '0', 1, 0], true)) {
return true;
}
return false;
}
/** * Get the validation error message. * * @return string */
public function message()
{
return trans('validation.custom.boolean');
}
}
以上就是今天踩的坑,筆記一下以免時間一久就忘記了。
github issues 參考
https://github.com/laravel/ideas/issues/514
filter_var 參考
https://www.php.net/manual/zh/function.filter-var.php