Przetwarzanie ciągu znaków na wartość logiczną w PHP

126

Dzisiaj bawiłem się w PHP i odkryłem, że wartości ciągów „true” i „false” nie są poprawnie przetwarzane na wartości logiczne w warunku, na przykład biorąc pod uwagę następującą funkcję:

function isBoolean($value) {
   if ($value) {
      return true;
   } else {
      return false;
   }
}

Jeśli wykonam:

isBoolean("true") // Returns true
isBoolean("") // Returns false
isBoolean("false") // Returns true, instead of false
isBoolean("asd") // Returns true, instead of false

Wydaje się, że działa tylko z wartościami „1” i „0”:

isBoolean("1") // Returns true
isBoolean("0") // Returns false

Czy w PHP istnieje natywna funkcja przetwarzająca ciągi „prawda” i „fałsz” na wartość logiczną?

znak
źródło
W twoim kodzie isBoolean("")powinno zwrócić false.
BoltClock
Powinieneś rozważyć zmianę zaakceptowanej odpowiedzi na odpowiedź Erica Carona. Pokazuje natywną funkcję, która robi to, o co prosisz.
Code Commander
1
PHP nie myśli o tym, co mówi łańcuch, „false” to tylko pięć znaków, które nic nie znaczą. Są jednak czymś , więc wartość logiczna ocenia się truetak, chociaż dla ludzkiego czytelnika wydawałoby się to bardziej intuicyjne, niż to oznaczało FALSE.
zeel

Odpowiedzi:

413

Jest to natywna metoda PHP, która wykorzystuje metodę filter_var PHP:

$bool = filter_var($value, FILTER_VALIDATE_BOOLEAN);

Zgodnie z instrukcją PHP :

Zwraca wartość TRUE dla wartości „1”, „true”, „on” i „yes”. W przeciwnym razie zwraca FALSE.

Jeśli ustawiono FILTER_NULL_ON_FAILURE, FALSE jest zwracane tylko dla „0”, „false”, „off”, „no” i „”, a NULL jest zwracane dla wszystkich wartości innych niż boolowskie.

Eric Caron
źródło
To powinna być akceptowana odpowiedź. Wbudowane funkcje PHP są lepsze niż tworzenie własnych. Nie musisz odkrywać koła na nowo! Szkoda, że ​​było już za późno: P
casraf
1
czy wartość porównania jest również mała?
Mobiletainment
3
@Mobiletainment, tak - obsługuje każdą obudowę, jaką możesz sobie wyobrazić dla wartości $ (false, FALSE, FalSe itp.)
Eric Caron
Borked testcase na moim końcu. Do porównania użyto == zamiast ===. Usunie mój wcześniejszy komentarz, aby nie mylić ludzi.
andig
6
Odpowiedź zaskoczyła mnie, ponieważ musisz dodać flagę FILTER_NULL_ON_FAILUREdo filter_var()funkcji i NIE zastępować jej FILTER_VALIDATE_BOOLEANtak, jak myślałem. W rezultacie otrzymam następujący kod, który $bool = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
załatwił sprawę
14

Powodem jest to, że wszystkie ciągi są trueprzeliczane na wartości logiczne, z wyjątkiem "0"i ""(pusty ciąg).

Następująca funkcja zrobi dokładnie to, co chcesz: zachowuje się dokładnie tak jak PHP, ale ocenia również ciąg "false"jako false:

function isBoolean($value) {
   if ($value && strtolower($value) !== "false") {
      return true;
   } else {
      return false;
   }
}

Dokumentacja wyjaśnia, że: http://php.net/manual/en/language.types.boolean.php :

Podczas konwersji na wartość logiczną następujące wartości są uważane za FAŁSZ:

  • sama wartość logiczna FAŁSZ
  • liczba całkowita 0 (zero)
  • pływak 0,0 (zero)
  • pusty ciąg i ciąg „0”
  • tablica z zerowymi elementami
  • specjalny typ NULL (w tym zmienne nieustawione)
  • Obiekty SimpleXML utworzone z pustych tagów

Każda inna wartość jest uważana za PRAWDA (w tym dowolny zasób).

Arnaud Le Blanc
źródło
2
+1 miło. (Mógłby wrzucić tam strolera, ale to wszystko.)
John Parker
Myślę, że middaparka oznaczała porównanie strtolower ($ value) z „false”. Przekazywanie dosłownego „fałszu” do strtolower jest trochę ... głupie? :)
Paul Dixon
@Paul Dixon Tak, właśnie o tym mówiłem. :-)
John Parker
2
@Marco - if ($ value && strtolower ($ value)! == "faux") {jeśli pracujesz po francusku; if ($ value && strtolower ($ value)! == "falsch") {po niemiecku; if ($ value && strtolower ($ value)! == "onwaar") {po holendersku ... możesz zrozumieć, dlaczego PHP nie ma tego wbudowanego w standardzie
Mark Baker
1
„wszystkie niepuste ciągi są zwracane jako prawda podczas konwersji na wartość logiczną, z wyjątkiem„ 0 ”.”
BoltClock
5

Tylko w PHP "0"lub pusty napis wymusza fałsz; każdy inny niepusty łańcuch wymusza wartość true. Z instrukcji :

Podczas konwersji na wartość logiczną brane są pod uwagę następujące wartości FALSE:

  • pusty ciąg i ciąg „0”

Musisz napisać własną funkcję do obsługi ciągów "true"vs "false". Tutaj zakładam, że wszystko inne jest domyślnie fałszywe:

function isBoolean($value) {
   if ($value === "true") {
      return true;
   } else {
      return false;
   }
}

Na marginesie, do którego można łatwo skondensować

function isBoolean($value) {
   return $value === "true";
}
BoltClock
źródło
4

Niedawno potrzebowałem „luźnej” funkcji konwersji wartości boolowskiej do obsługi łańcuchów, takich jak te, o które pytasz (między innymi). Znalazłem kilka różnych podejść i wymyśliłem duży zestaw danych testowych, aby je przejrzeć . Nic nie pasowało do moich potrzeb, więc napisałem własne:

function loosely_cast_to_boolean($value) {
    if(is_array($value) || $value instanceof Countable) {
        return (boolean) count($value);
    } else if(is_string($value) || is_object($value) && method_exists($value, '__toString')) {
        $value = (string) $value;
        // see http://www.php.net/manual/en/filter.filters.validate.php#108218
        // see https://bugs.php.net/bug.php?id=49510
        $filtered = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        if(!is_null($filtered)) {
            return $filtered;
        } else {
            // "none" gets special treatment to be consistent with ini file behavior.
            // see documentation in php.ini for more information, in part it says: 
            // "An empty string can be denoted by simply not writing anything after 
            // the equal sign, or by using the None keyword".
            if(strtolower($value) === 'none') {
                $value = '';
            }
            return (boolean) $value;
        }
    } else {
        return (boolean) $value;
    }
}

Zauważ, że w przypadku obiektów, które są zarówno policzalne, jak i rzucane na łańcuchy, będzie to faworyzować liczenie względem wartości ciągu w celu określenia prawdziwości. Oznacza to, że jeśli $object instanceof Countablezwróci to (boolean) count($object)niezależnie od wartości (string) $object.

Możesz zobaczyć zachowanie danych testowych, których użyłem, a także wyniki dla kilku innych funkcji tutaj . Trudno jest przejrzeć wyniki z tego małego elementu iframe, więc zamiast tego można wyświetlić wynik skryptu na pełnej stronie (ten adres URL jest nieudokumentowany, więc może to nie działać wiecznie). Na wypadek, gdyby te linki pewnego dnia umarły, umieściłem kod również na pastebinie .

Granica między tym, co „powinno być prawdą”, a tym, co nie powinno, jest dość arbitralna; dane, których użyłem, są kategoryzowane w oparciu o moje potrzeby i preferencje estetyczne, Twoje mogą się różnić.

Matt Kantor
źródło
Ta funkcja działa bez zarzutu, dziękuję! Ale twoje linki to teraz 404.
servermanfail
3

Używam tej konstrukcji do przekształcania ciągów znaków w wartości logiczne, ponieważ w trueprzypadku większości innych wartości chcesz :

$str = "true";
$bool = !in_array($str, array("false", "", "0", "no", "off"));
mario
źródło
1

Czy w PHP jest funkcja przetwarzająca ciągi „prawda” i „fałsz” na wartość logiczną?

Nie - oba są łańcuchami i oba (jak mówisz) obliczają true. falseW PHP obliczane są tylko puste łańcuchy .

Musisz to sprawdzić ręcznie. Jeśli to w ogóle możliwe, lepiej byłoby zamiast tego pracować z „prawdziwymi” wartościami boolowskimi.

Pekka
źródło
1
trueW PHP nie wszystkie łańcuchy są oceniane na .
coreyward
1
Nie poprawiałam, tylko wyjaśniałam. Powiedzenie „oba są łańcuchami [i obliczane na true]” może dać nowicjuszowi niewłaściwe wrażenie, szczególnie w innym języku z bardziej rygorystycznymi regułami pisania, w których ciąg jest łańcuchem, a zawartość nie ma znaczenia, gdy jest konwertowany na wartość logiczną (np. Rubin).
coreyward
1
„Tylko puste łańcuchy oznaczają fałsz w PHP”. Ale co z niepustym łańcuchem "0"? Czy to również nie daje false?
Sepster
0

Najłatwiejszy sposób na bezpieczną konwersję na wartość logiczną;

    $flag = 'true';

    if( filter_var( $flag,FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE ) !== null) {
      $flag = filter_var($flag,FILTER_VALIDATE_BOOLEAN);
    }

    gettype($flag); // Would Return 'Boolean'
    echo 'Val: '.$flag; // Would Output 'Val: 1'
Timothy Perez
źródło
0

Jeśli Twój interfejs API akceptuje tylko ciągi „prawda” lub „fałsz”, a wszystko inne staje się innenull , spróbuj:

$boolean = ['true' => true, 'false' => false][$inputString] ?? null;

Zakłada się, że $inputnie jest to przedmiot. Null coalesce ( ??) została wprowadzona w PHP 7.0.

Matt Janssen
źródło