Нечетное поведение оператора switch

Я пишу код для сортируемой таблицы, где щелчок по ссылкам в заголовке изменяет ORDER BY, выполняемый при генерации набора результатов поиска (случай, когда там нет действительного порядка, заставляя запрос не запускаться с порядком и просто вернуть результаты в порядке возврата базы данных, как это предусмотрено). Код записывается в рамках, предоставленных моим работодателем.

Чтобы проверить часть запроса ORDER BY, я запускаю вход через следующую функцию проверки.

<?php
function sortMode ($name)
{
    $mode   = '';
    switch ($name)
    {
        case 'resnum'   : $mode = 'b_resnum';            break;
        case 'state'    : $mode = 'st_id';               break;
        case 'name'     : $mode = 'lastname, firstname'; break;
        case 'phone'    : $mode = 'phone';               break;
        case 'email'    : $mode = 'email';               break;
        case 'opened'   : $mode = 'cs_created';          break;
        default         : $mode = '';                    break;
    }
    return ($mode);
}
?>

При тестировании я обнаружил, что если параметр не был предоставлен, порядок сортировки будет resnum. После некоторых экспериментов я обнаружил, что фильтрация, встроенная в фреймворк, вызовет запрос для неинициализированной переменной, такой как параметр unset GET, для возврата целого числа 0. Если вышеприведенный код получил питание в качестве его целого числа, он всегда будет следовать за первым путь выполнения, доступный для него.

В качестве эксперимента я попытался переупорядочить порядок дел в инструкции switch и нашел, что было наверху, это то, что было выполнено, если эта функция была передана 0.

Решение проблемы состояло в использовании switch (strval($name)), поэтому конкретная проблема решена, но теперь мне любопытно относиться к общему поведению операторов переключения PHP. Является ли поведение я свидетелем правильного поведения для PHP? Есть ли какая-то ошибка в PHP, которая вызывает это, или я сделал ошибку в своем коде, о котором я не знаю?

Ответ 1

Это из-за того, как php передает строки в int. Когда вы передаете 0, вы просите его выполнить целочисленное сравнение, поэтому он преобразует все ваши ключи к целым. Когда php отправляет a string в int, он ищет фактическое число в начале строки и подбирает число до тех пор, пока оно не достигнет числа, отличного от числа. Так как строка "resnum" не имеет чисел, она возвращает 0. См. Здесь:

php > echo (int)"100";
100
php > echo (int)"300 dogs";
300
php > echo (int)"resnum";
0
php > echo (int)"resnum 100";
0

Так как все эти строки, отнесенные к 0, первый случай будет оцениваться с true с 0 == 0.

Ресурсы
Преобразование строк в числа
Таблица сравнения типов


Время Nitpick. Когда вы делаете простые операторы case, которые отображают строку в строку, используйте массив. Это намного яснее и быстрее:

function sortMode ($name)
{
    $modeMap = array(
        'resnum'   => 'b_resnum',
        'state'    => 'st_id',
        'name'     => 'lastname, firstname',
        'phone'    => 'phone',
        'email'    => 'email',
        'opened'   => 'cs_created'
    );

    return isset($modeMap[$name]) ? $modeMap[$name] : '';
}

Если на карте установлено значение $name, мы возвращаем значение, к которому привязан ключ. В противном случае мы возвращаем пустую строку, которая заменяет случай default.

В качестве бонуса вы заметили бы ошибку раньше, если бы вы сделали вышеуказанный метод, потому что он пытался получить доступ к $modeMap[0] и вместо этого вернул бы ваш случай по умолчанию.

Ответ 2

Ключевым моментом является то, что оператор switch() выполняет сравнение между параметром и метками. Это означает, что вам приходится иметь дело с правилами сравнения и выбора типов PHP. Просто посмотрите несколько примеров:

<?php

var_dump( ''==0 );    // bool(true)
var_dump( 'foo'==0 ); // bool(true)
var_dump( '0'==0 );   // bool(true)
var_dump( '0m'==0 );  // bool(true)
var_dump( '01'==0 );  // bool(false)

Ссылка может быть найдена по адресу:

Инициализация не заданного параметра GET до 0 - довольно странное дизайнерское решение. Вы должны разобраться с этим конкретным случаем отдельно, чтобы было ясно, что это особая ситуация:

if( $name===0 ){
    return '';
}
switch($name){
    // ...
}