SWITCH & reurn(0) & CASE string

  • Автор темы Автор темы alpes
  • Дата начала Дата начала

alpes

Весь мир на ладони
SWITCH & reurn(0) & CASE string

Имеем вот такой пример:
PHP:
function a()
{
  for($i=0;$i<4;$i++)
  switch(b($i))
  {
    case "text2": echo "'2' text<br>"; break;
    case "text3": echo "'3' text<br>"; break;
    default: echo "'$i'<br>";
  }
}
function b($v)
{
  if($v==2) return("text2");
  if($v==3) return("text3");
  return($v);
}

a();
По логике на выходе должны получить:
---------
'0'
'1'
'2' text
'3' text
---------
А не тут-то было :( выводится:
---------
'2' text
'1'
'2' text
'3' text
---------

Собственно что это за аномалия?! Почему return(0) приводится к первой строке кейса?

PS. Из мана:
PHP:
The case expression may be any expression that evaluates to a simple type, that is, integer or floating-point numbers and strings.
 
А зачем перед 2 или 3 ставить одинарные кавычки?
И вот это зачем? - "'\$i'<br>"; Не проще так написать - "\$i<br>"; или еще проще - '$i<br>'; Здесь наверное и ошибка.
Попробуй вот так:
default: echo "$i<br>";
 
alpes - дело в сравнении и типах данных (только что эксперимент произвел :)
У тебя в switch-е сравнение идет либо в числовой форме либо в строковой (соответственно, когда возвращаем строку или число), так вот при сравнении числа с чем-то, второй аргумент тоже привозится к числу (а строки твои как раз и преобразуютя в нули). Решение: в функции b поменять последнюю строку на:
return((string)$v);
или
return("$v");

Вот и все :) Если непоятно объяснил, спроси, что не понял :)
 
Как появилось \$, понятия не имею, использовал Ctrl+C & Ctrl+V для вставки кода примера, в исходнике слэша перед $ нет, будем считать опечаткой.

На счет преобразования типов:
Если второй аргумент приводится к первому типу, то тогда почему происходят эти же грабли и наоборот:
PHP:
function a()
{
  for($i=0;$i<4;$i++)
  switch(b($i))
  {
    case 0: echo "case '0'<br>"; break;
    case "text2": echo "'2' text<br>"; break;
    case "text3": echo "'3' text<br>"; break;
    default: echo "'$i'<br>";
  }
}
function b($i)
{
if($i==2) return("text2");
if($i==3) return("text3");
return($i);
}

a();
Вместо:
---------
case '0'
'1'
'2' text
'3' text
---------
Имеем:
---------
case '0'
'1'
case '0'
case '0'
---------

2Profic, как обойти - это не проблема.
Хочу знать почему ЭТО происходит?!! Или в switch моно использовать значения только одного типа и это фича?
 
Сдается строки вообще не стоит использовать в switch! Вернет какая-то функция в случае какой-то ошибки в программе число 0, а в switch вместо дефолта выведет совсем не то!!!
 
alpes, это происходит понятно почему - преобразование типов, но к сожалению в мануале по PHP не написано, что к чему точно приводится при сравнении (а тут идет именно сравнение первого аргумента (в switch) со вторым (в case)), по крайней мере я не нашел (вот, к примеру, в мануале по JavaScript-у такое описание есть).

Появилась идея, что все сравнивание идет в типе первого case-а (что подтвердает, указание в мануале на то, что выражение в switch вычисляется только раз и потом приводится к типу первого case), из этого следует, что в case-е можно использовать только переменные одного типа, а для переменных разных типов использовать пачку if-elseif...

Я предполагаю, что эта багофича есть плата за единственное вычисление аргумента switch-а, т.к. представь, например:
switch ($var) {
case 'string': ...
case 1: // число
case true: // булево
case 'string2': ...
}
и если при сравнении каждый раз приводить $var к типу сравниваемого case-а, то к 4 case-у переменная $var потеряет свое перваначально значение...

ЗЫ. Это мое личное мнение, т.к. в исходники не заглядывал (а надобы), а в мануале этого не описано...
 
Мда, чудеса...
Скорее все таки это бага, так что вообще теряется будь-какая логика - что к чему уже приводится:
PHP:
#меняем местами 1-ю и 2-ю строки примера и смотрим как от этого меняется выводимый результат, просто очевидное не вероятное:
    case "text2": echo "'2' text<br>"; break; 
    case 0: echo "case '0'<br>"; break; 
    case "text3": echo "'3' text<br>"; break;
------
case '0'
'1'
'2' text
case '0'
------
 
А поставь
case 0: echo "case '0'<br>"; break;
последней, т.е.
case "text2": echo "'2' text<br>"; break;
case "text3": echo "'3' text<br>"; break;
case 0: echo "case '0'<br>"; break;

Но логика, по крайней мере мне непонятна... :(

Блин, где наши боги? :) (это я имеюю ввиду тех у кого сообщений здесь за 1000 :))
 
alpes, Profic, что вы несете. Какая фича, какая бага? Вам понятно почему это происходит "преобразование типов". Что вам еще надо? Наговорить ерунды и сосвсем запутаться в ваших предположениях? Подумайте как работает функция switch... Вам что описать логику работы этой функции или вы сами додумаетесь?
 
Кром, я прочитал описание логики работы switch, которая описана в мануале PHP, но что к чему приводится непонятно... если знаешь колись :)
 
1) The switch statement executes line by line (actually, statement by statement). In the beginning, no code is executed. Only when a case statement is found with a value that matches the value of the switch expression does PHP begin to execute the statements.
2) In a switch statement, the condition is evaluated only once and the result is compared to each case statement.

Внимание вопрос: что к чему приводится? Из описания совершенно непонятно. Это просто английские слова, не более :(

ЗЫ. Может я и торможу после праздников, но видимо, как-то сильно :)
 
Цифра 0
Идет сравнение с первой строкой
case "text2": echo "'2' text<br>"; break;
в этой строке 0 == intval("text2")
Это понятно? И switch здесь не при чем!!!
Возвращается '2' text, так как в первой строке обнаружено равенство!

Цифра 1
Идет сравнение с первой строкой: 1 != 0 -- intval("text2")
Идет сравнение со второй строкой: 1 != 0 -- intval("text3")
Возвращается 1

Цифра 2
Идет сравнение с первой строкой: text2 == text2
Возвращается '2' text

Цифра 3
Идет сравнение с первой строкой: text3 != text2
Идет сравнение со второй строкой: text3 == text3
Возвращается '3' text
 
2Кром, боюсь ты вообще не вник в суть вопроса. Ресь идет не о логике работы switch, а о том какой тип к какому приводится и почему в одном случае при string 'так', а в другом при int ноль 'так'. Всмотрись в примеры.
 
Все, блин, я въехал :)
Какой-то чел в комментариях к switch на www.php.net написал, что при сравнении числа и строки, строка преобразуется в число, в независимости от их порядка (правый или левый аргумент).

Первый вариант я расписал (да и Кром тоже), а во втором варианте строки сравниваются вначале с нулем, и, следовательно, они равны вот и получется, то что мы видим :)

ЗЫ. Этой гемогогии не было бы, если бы где-нить в мануале по PHP было бы написано, что к чему приводится при сравнении...

alpes, про твое высказываение "Сдается строки вообще не стоит использовать в switch! Вернет какая-то функция в случае какой-то ошибки в программе число 0, а в switch вместо дефолта выведет совсем не то!!!"
Если в switch-е используются только строки, то нужно switch писать так:
switch ((string) $var) {
...
}
 
alpes, это как говорится хозяйке на заметку.
"Если один из операндов логического оператора может трактоваться как число, то оба операнда трактуются как числа".
Прочти это несколько раз, потом всмотрись в примеры и попробуй понять почему в одном случае так, а в другом эдак.
 
Profic, это основы PHP, операции сравнения. И их логика распространяется на все функции.
 
Я понимаю, что это основы PHP, но где об этом написано?
Хотя вот нашел фразу:
If any of the operands is a float, then all operands are evaluated as floats, and the result will be a float. Otherwise, the operands will be interpreted as integers, and the result will also be an integer.
Но там описывается операция "+"...
Блин, в мануале этой информации явно недостает...

Ладно, проехали... :)
 
Да, теперь все стало на свои места, что и почему происходит.
Удобно конечно было бы ф-ию switch немного изменить: если присутствуют внутри кейсов строковые операнды, то преобразовывать передаваемое значение к стрингу... но если аккуратно работать - это все же лишнее.
Всем спасибо. :)
 
Сверху