Странности в работе с массивом

pitaval

Guest
Странности в работе с массивом

Доброе время суток всем доблестным программистам, пишущим на PHP!
Два дня назад, при написании кода для довольно-таки большого проекта я столкнулся
со странной проблемой, на решение которой у меня ушло два дня (с перерывами на
сон и принятие пищи). Был произведен дебаггинг, трассировка на бумаге и все все все,
что могло бы выявить ошибку в коде. Но ничего не помогло. В результате решение
появилось у меня совершенно случайно.
Суть проблемы заключается в том, что PHP начинает вести себя очень странно (проще
говоря, безобразно) при проверке элементов массива-коллекции, в котором есть индекс
ноль, с нулевым значением. Проверку я запустил в цикле foreach, проверял и switch'ем и if'ом.
В обоих случаях, при проверке значения нулевого индекса (со значением ноль) выражение
вычисляется в TRUE.
Вот простой пример. Реальный пример был гораздо сложнее и касался безопасности, т.к. про-
верялись поля на наличие флажка проверки (ISFILL).

$my_arr["a"]=array("ISFILL", 1, 2, 3);
$my_arr["b"]=array(0, 1, 2, 3);

foreach($my_arr as $k=>$v)
{
if($my_arr[$k][0]=="ISFILL"){ echo "Проверка требуется!"; }else{ echo "Проверка не требуется..."; }
}

Вот что идет на аутпуте:
Проверка требуется!
Проверка требуется!

Хотя, по логике вещей в первом случае у нас стоит флажок "ISFILL" и это поле надо проверить,
а во втором случае у нас нет флажка и вместо него значение ноль.
Если во втором поле ($my_arr["b"]) изменить значение нулевого элемента на 1, то все пойдет
как по маслу.
Второй вариант исправления ошибки, это заменить операцию "равно" (= =) на "идентично" (= = =)
Но тут тоже возникает вопрос о странном поведении PHP, ведь "ISFILL"- это строка, а 0- целое...
Самое ужасное во всей этой истории- мои ощущения, когда я смотрю на абсолютно правильный код
и не понимаю, почему он не работает.
Может кто-то знает в чем кроется причина таких странностей.
Версия интерпретатора 4.3.2.2. Система- WinXP, сервер- Apache
 

SiMM

Новичок
> Второй вариант исправления ошибки, это заменить операцию "равно" (= =) на "идентично" (= = =)
> Но тут тоже возникает вопрос о странном поведении PHP, ведь "ISFILL"- это строка, а 0- целое...
И в чём же заключается странность при использовании '==='? Имхо, всё как надо.
PS: на PHP 4.3.9/Win/*nix - повторилось. А вообще пример гораздо проще
PHP:
var_dump(0=="ISFILL");
 

pitaval

Guest
Originally posted by SiMM
> Второй вариант исправления ошибки, это заменить операцию "равно" (= =) на "идентично" (= = =)
> Но тут тоже возникает вопрос о странном поведении PHP, ведь "ISFILL"- это строка, а 0- целое...
И в чём же заключается странность при использовании '==='? Имхо, всё как надо.

А странность в том, что ISFILL- string, a 0- integer

PS: на PHP 4.3.9/Win/*nix - повторилось. А вообще пример гораздо проще
PHP:
var_dump(0=="ISFILL");
 

SiMM

Новичок
> А странность в том, что ISFILL- string, a 0- integer
Ну и что? Поведение ничуть не отличается от описанного в мануале в разделе Операторы сравнения. Что же касается вашего "затыка" - то всё правильно, читайте раздел Приведение типов - судя по всему, при сравнении происходит попытка преобразовать string в int, а это, очевидно, даст 0
 

pitaval

Guest
И вообще, я все-таки никак не могу понять такое странное поведение PHP

-~{}~ 12.02.05 21:23:

Так ведь чем отличается равно от идентично, тем что происходит еще и сравнение типов, а они у нас разные... И почему же происходит typecasting, я перечитал мануал много раз, там такие случаи не описанны

-~{}~ 12.02.05 21:26:

при приведении (int)ISFILL получается 1
 

SiMM

Новичок
> Так ведь чем отличается равно от идентично, тем что происходит еще и сравнение типов, а они у нас разные...
"Равно" от "идентично" отличается тем, что
а) не происходит преобразования типов
б) если типы неравны, результат - false, в противном случае результатом будет результат "равно".

> И почему же происходит typecasting
Потому что это происходит всегда, когда типы аргументов неодинаковы. Да, правил, когда во что преобразуется, я, кстати, тоже не нашёл - но это можно списать на недостаток мануала - ни что не идеально в этом мире.

> при приведении (int)ISFILL получается 1
Это клевета - не вводите нас в заблуждение
PHP:
<?=(int)"ISFILL"?>
 

pitaval

Guest
Да это конечно интересно, если происходит приведение типов, но мне от этого не легче, это что же получается, если я перед этим проверял строчку а потом проверяю число, то без моего ведома происходит приведение типов?
 

SiMM

Новичок
Это получается, что надо использовать ===. А что ты проверял перед этим или будешь проверять потом - PHP совершенно по барабану.
 

pitaval

Guest
Тогда вопрос- почему происходит приведение типов?
 

SiMM

Новичок
Потому что типы разные :)
Ты бы читал чтоли внимательнее, что тебе пишут, в том числе - мануал.
http://php.net/manual/ru/language.types.type-juggling
PHP не требует (и не поддерживает) явного определения типа при объявлении переменной; тип переменной определяется по контексту, в котором она используется.
 

pitaval

Guest
Я это знаю, но почему при проверке string переменной контекст как у int переменной?
 

SiMM

Новичок
> почему при проверке string переменной контекст как у int переменной?
Потому что она сравнивается с int'ом.
Гибкое сравнение с помощью ==
PS: До осмотра таблиц, важно знать и понимать типы переменных и их значения. К примеру, "42" -- строка, в то время как 42 -- целое. FALSE -- логическое, а "false" -- строка.
 

pitaval

Guest
Теперь понял, но только после прочтения комментария внизу:
The way PHP handles comparisons when multiple types are concerned is quite confusing.

For example:
"php" == 0

This is true, because the string is casted interally to an integer. Any string (that does not start with a number), when casted to an integer, will be 0.


-~{}~ 12.02.05 22:16:

Только вот теперь остается мне везде что-ли писать === вместо ==, ведь я работаю со смешанными типами данных?
 

SiMM

Новичок
> For example: "php" == 0
Собственно, в таблице это написано ;)

> Только вот теперь остается мне везде что-ли писать
> === вместо ==, ведь я работаю со смешанными
> типами данных?
Здесь нельзя дать однозначного ответа - вопрос решается в индивидуальном порядке для каждого случая.
 

pitaval

Guest
ИМХО, это очень неудобно менять типы во время проверок

-~{}~ 12.02.05 22:22:

И теперь придется переписвыть большое кол-во кода:(
 

SiMM

Новичок
> ИМХО, это очень неудобно менять типы во время проверок
А их и не надо менять.

> И теперь придется переписвыть большое кол-во кода
Не факт. Да и чтож поделаешь - та же ситуация раньше случалась с register_globals - кто ж виноват, что ты этого не знал/не думал над этим?
 
Сверху