2023-09-27|閱讀時間 ‧ 約 6 分鐘

Laravel 內建 Boolean validation 不接受 'true', 'false'

最近在開發某一個項目功能,這也是先前同事踩到的坑,這次換我在踩一次,順便記錄一下,主要發生情境是,在執行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




分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.