SWITCH & reurn(0) & CASE string

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.
 

MikeV

Guest
А зачем перед 2 или 3 ставить одинарные кавычки?
И вот это зачем? - "'\$i'<br>"; Не проще так написать - "\$i<br>"; или еще проще - '$i<br>'; Здесь наверное и ошибка.
Попробуй вот так:
default: echo "$i<br>";
 

Profic

just Profic (PHP5 BetaTeam)
alpes - дело в сравнении и типах данных (только что эксперимент произвел :)
У тебя в switch-е сравнение идет либо в числовой форме либо в строковой (соответственно, когда возвращаем строку или число), так вот при сравнении числа с чем-то, второй аргумент тоже привозится к числу (а строки твои как раз и преобразуютя в нули). Решение: в функции b поменять последнюю строку на:
return((string)$v);
или
return("$v");

Вот и все :) Если непоятно объяснил, спроси, что не понял :)
 

alpes

Весь мир на ладони
Как появилось \$, понятия не имею, использовал 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 моно использовать значения только одного типа и это фича?
 

alpes

Весь мир на ладони
Сдается строки вообще не стоит использовать в switch! Вернет какая-то функция в случае какой-то ошибки в программе число 0, а в switch вместо дефолта выведет совсем не то!!!
 

Profic

just Profic (PHP5 BetaTeam)
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 потеряет свое перваначально значение...

ЗЫ. Это мое личное мнение, т.к. в исходники не заглядывал (а надобы), а в мануале этого не описано...
 

alpes

Весь мир на ладони
Мда, чудеса...
Скорее все таки это бага, так что вообще теряется будь-какая логика - что к чему уже приводится:
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'
------
 

Profic

just Profic (PHP5 BetaTeam)
А поставь
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... Вам что описать логику работы этой функции или вы сами додумаетесь?
 

Profic

just Profic (PHP5 BetaTeam)
Кром, я прочитал описание логики работы switch, которая описана в мануале PHP, но что к чему приводится непонятно... если знаешь колись :)
 

Profic

just Profic (PHP5 BetaTeam)
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
 

alpes

Весь мир на ладони
2Кром, боюсь ты вообще не вник в суть вопроса. Ресь идет не о логике работы switch, а о том какой тип к какому приводится и почему в одном случае при string 'так', а в другом при int ноль 'так'. Всмотрись в примеры.
 

Profic

just Profic (PHP5 BetaTeam)
Все, блин, я въехал :)
Какой-то чел в комментариях к switch на www.php.net написал, что при сравнении числа и строки, строка преобразуется в число, в независимости от их порядка (правый или левый аргумент).

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

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

alpes, про твое высказываение "Сдается строки вообще не стоит использовать в switch! Вернет какая-то функция в случае какой-то ошибки в программе число 0, а в switch вместо дефолта выведет совсем не то!!!"
Если в switch-е используются только строки, то нужно switch писать так:
switch ((string) $var) {
...
}
 

Кром

Новичок
alpes, это как говорится хозяйке на заметку.
"Если один из операндов логического оператора может трактоваться как число, то оба операнда трактуются как числа".
Прочти это несколько раз, потом всмотрись в примеры и попробуй понять почему в одном случае так, а в другом эдак.
 

Кром

Новичок
Profic, это основы PHP, операции сравнения. И их логика распространяется на все функции.
 

Profic

just Profic (PHP5 BetaTeam)
Я понимаю, что это основы 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.
Но там описывается операция "+"...
Блин, в мануале этой информации явно недостает...

Ладно, проехали... :)
 

alpes

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