зробити перемикач використовувати === порівняння не == порівняння У PHP


78

Чи є спосіб зробити так, щоб наступний код все ще використовував комутатор, а bне повертав a? Дякую!

$var = 0;
switch($var) {
    case NULL : return 'a'; break;
    default : return 'b'; break;
}

Звичайно, використовуючи оператори if, ви робите це так:

$var = 0;
if($var === NULL) return 'a';
else return 'b';

Але для більш складних прикладів це стає багатослівним.

Відповіді:


55

На жаль, ви не можете використовувати ===порівняння в операторі switch, оскільки згідно з документацією switch () :

Зверніть увагу, що перемикач / корпус нещільне порівняння.

Це означає, що вам доведеться придумати обхідний шлях. З таблиці вільних порівнянь ви можете скористатися фактом, який NULL == "0"є хибним за типом лиття:

<?php
$var = 0;
switch((string)$var) 
{
    case "" : echo 'a'; break; // This tests for NULL or empty string   
    default : echo 'b'; break; // Everything else, including zero
}
// Output: 'b'
?>

Демо в прямому ефірі


1
Ну, є й інші обставини (не лише з NULL), з якими я хотів би, щоб це працювало.
Аарон Йодайкен

18

Ось ваш оригінальний код у "строгому" викладі:

switch(true) {
    case $var === null:
        return 'a';
    default:
        return 'b';
}

Це також може обробляти більш складні оператори перемикання, наприклад:

switch(true) {
    case $var === null:
        return 'a';
    case $var === 4:
    case $var === 'foobar':
        return 'b';
    default:
        return 'c';
}

8

Не з switch- він робить лише так звані "вільні" порівняння. Ви завжди можете замінити його на if/else ifблок, використовуючи ===.


Ви посилаєтесь на свій досвід чи документацію? Якщо пізніше, будь ласка, опублікуйте посилання
TMS

1
Ви насправді можете це зробити switch(див. Мою відповідь), хоча я думаю, що if-elseце краще для цієї конкретної роботи.
DaveRandom

Багато хороших відповідей, вибачте, я можу вибрати лише 1. Я пішов із if / elseif дякую всім.
yar matie

Насправді не "завжди" :) Що робити, якщо не у всіх регістрових блоках є breakабо return?
Шторм

3

Імовірно, ви вмикаєте змінну і очікуєте цілих чисел. Чому б просто не перевірити цілий статус змінної заздалегідь, використовуючи is_int($val) ?


3

У мене була та ж проблема в комутаторі з рядком, що містить числа ("15.2" дорівнює "15.20" у комутаторі для php)

Я вирішив проблему, додавши літеру перед текстом для порівняння

$var = '15.20';
switch ('#'.$var) {
    case '#15.2' :
      echo 'wrong';
    break;
    case '#15.20' :
      echo 'right';
    break;
}

1

зробити перемикач використовувати === порівняння не == порівняння У PHP

На жаль, switchвикористовується вільне порівняння, і, наскільки я знаю, змінити це неможливо.



1

Я просто використовую

$var === null and $var = -1; // since switch is not type-safe
switch ( $var ) {
    case 0:
        # this tests for zero/empty string/false
        break;
    case -1:
        # this tests for null
        break;
}

Я думаю, це все ще виглядає дуже читабельним, якщо коментар, що починається з //, залишається позаду (а ті, що починаються з #, напевно, найкраще видалити).


1

Ні. На сторінці керівництва :

Зверніть увагу , що перемикач / випадок робить пухке порівняння .

Якщо у вас лише дві умови, скористайтеся ifподібним вашим другим прикладом. В іншому випадку перевірте NULLперший і ввімкніть інші можливості:

if (is_null($var))
{
  return 'a';
}

switch ($var)
{
    // ...
}

1

Екстраполюючи з вашого прикладу коду, я думаю, у вас є купа звичайних випадків та один особливий випадок (тут, null).

Найпростіше, що я можу зрозуміти, - це розглянути цю справу перед перемиканням:

if ($value === null) {
    return 'null';
}

switch ($value) {
    case 0:
        return 'zero';
    case 1:
        return 'one';
    case 2:
        return 'two';
}

Можливо, також додайте коментар, щоб пам’ятати, він nullби несподівано відповідав 0справі (також навпаки, 0відповідав би nullвипадку).


1

Так. На PHP 8 ви можете зробити це за допомогою matchоператора.

На відміну від switch, порівняння - це перевірка ідентичності (===), а не слабка перевірка рівності (==). Вирази відповідності доступні з PHP 8.0.0.

Дивіться тут: https://www.php.net/manual/en/control-structures.match.php

$var=0;
echo match ($var) {
    NULL=> 'a',
    default => 'b'
};

0

Це неможливо.

Ви можете, однак, покласти ifзаяви всерединіswitch :

switch($var) {
    // Loose cases here

    case 0:
        if($var === NULL) {
            return 'a';
        }

        // Fall through

    default:
        return 'b';
}

Або просто:

switch($var) {
    // Loose cases here

    default:
        if($var === NULL) {
            return 'a';
        }

        return 'b';
}

7
У цей момент навіщо турбуватися про перемикач? Ви навіть можете зробити `switch (true) {case $ var === null: ...}
ircmaxell

1
@ircmaxell, я припустив, що операційна система бажає проникнення логіки або іншої причини, яку слід використовувати switchпоза строгою перевіркою часом.
Strager

0

Ви також можете ввімкнути тип змінної:

switch (gettype($var)) {
...
}

Погана ідея - З документації:Never use gettype() to test for a certain type, since the returned string may be subject to change in a future version. In addition, it is slow too, as it involves string comparison. Instead, use the is_* functions.
Пітер Айтай

Якщо gettype () зміниться, це зробить функцію марною, а мову менш надійною. Використання is_ * не дає відповіді на питання про комутатор. В іншому я погоджуюсь :)
greg

0

Одним з найкращих способів є перевірка значення NULL за допомогою is_null

<?php
echo getValue();
function getValue()
{
    $var = 0;   
    switch(true) {
        case is_null($var) : return 'a'; break;
        default : return 'b'; break;
    }
}
?>

1
Однак найкраще, === nullоскільки це дозволяє уникнути непотрібних накладних викликів функції.
Antti29,

0

Створіть клас, схожий на твердження, і вкладіть у нього будь-яку логіку; доки повертаються "істинні" методи $this(і нічого іншого, щоб уникнути помилкових спрацьовувань.)

class Haystack
{
    public $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    public function isExactly($n)
    {
        if ($n === $this->value)
            return $this;
    }
}

$var = new Haystack(null);

switch ($var) {
    case $var->isExactly(''):
        echo "the value is an empty string";
        break;

    case $var->isExactly(null):
        echo "the value is null";
        break;
}

Або ви можете помістити свій перемикач у власне клас:

class Checker
{
    public $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    public function isExactly($n)
    {
        if ($n === $this->value)
            return $this;
    }

    public function contains($n)
    {
        if (strpos($this->value, $n) !== false)
            return $this;
    }

    public static function check($str)
    {
        $var = new self($str);

        switch ($var) {
            case $var->isExactly(''):
                return "'$str' is an empty string";
            case $var->isExactly(null):
                return "the value is null";
            case $var->contains('hello'):
                return "'$str' contains hello";
            default:
                return "'$str' did not meet any of your requirements.";
        }
    }
}

var_dump(Checker::check('hello world'));   # string(28) "'hello world' contains hello"

Звичайно, у цей момент ви можете переоцінити те, що ви хочете зробити з тим, що ви перевіряєте, і замість цього використати справжню бібліотеку перевірки.


0

Якщо ви хочете перевірити як значення, так і тип вашої змінної, тоді створіть нову змінну рядка, що містить обидві інформації, і порівняйте її з різними сценаріями (шляхом конкатенації), вона повинна працювати для вашого випадку, якщо ви реалізуєте всі можливі типи (відповідно до gettype ( ) документація ), приклад:

<?php
    $var= 9999;
    $valueAndTypeOfVar = (string)$var.' '.gettype($var);
    switch($valueAndTypeOfVar) {
        case "$var boolean" : echo 'a'; break;
        case "$var integer" : echo 'b'; break; 
        case "$var double" : echo 'c'; break;
        case "$var string" : echo 'd'; break; 
        case "$var array" : echo 'e'; break;
        case "$var object" : echo 'f'; break; 
        case "$var resource" : echo 'g'; break;
        case "$var NULL" : echo 'h'; break; 
        case "$var unknown type" : echo 'i'; break; 
        default: echo 'j'; break;
    }

   // Outputs: 'b'
?>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.