Неожиданное поведение внутри цикла foreach

GRIG

Новичок
Неожиданное поведение внутри цикла foreach

Помогите разобраться с очередной непоняткой.
Пишу скрипт, который клеит SQL-запрос из кусков строки, посылает его в оракловую базу и как-то выдает результаты на экран. Одна из функций скрипта - подклеивать к запросу разные дополнительные условия в зависимости от того, что выбрал пользователь на экране. Делаю это все по следующей методике:
1) Начальная инициализация - завожу два пустых массива:
$conditions = Array();
$vallist = Array();
2) Проход по пользовательским настройкам. Для каждой настройки, которая влияет на текст запроса, делается примерно следующее:
$conditions[] = 'MYFIELD = :myvalue';
$vallist[ ':myvalue' ] = значение из настройки
3) Подклейка условий к запросу
$sql = основной текст запроса
if( count( $conditions ) > 0 )
{
$sql .= "WHERE " . implode( $conditions, ' AND ' );
}
$sql .= что-то на тему сортировки
4) Передача запроса на исполнение
$stmt = ociparse( $conn, $sql );
foreach( $vallist as $key => $val )
{
(вариант а) ocibindbyname( $stmt, $key, $vallist[$key] );
(вариант б) ocibindbyname( $stmt, $key, $val );
}
ociexecute( $stmt );
$num = ocifetchstatement( $stmt, $result );
и дальше выдача найденного на экран
Неожиданно для себя обнаружил, что вариант а работает нормально, а вариант б работает ненормально. В варианте б база запросто может вернуть не те данные, которые нужны или вообще сказать "не найдено", хотя данные есть. Хотя (по идее) разницы между вариантами совсем никакой.
Чего я тут не понимаю?
 

GRIG

Новичок
За замечание спасибо. Но это не то. Во-первых, implode может принимать свои параметры в любом порядке (так написано вот здесь: http://ru.php.net/manual/en/function.implode.php). Во-вторых, я писал в лог получившийся SQL-запрос, а также передаваемые ему параметры - ничего подозрительного не видно. Более того, подавал получившийся запрос "руками" через Oracle SQL Developer - выдается все, что нужно.
 

crocodile2u

http://vbolshov.org.ru
LeoKee
Надо думать, что это просто издержки того, что код, который мы видим, написан непосредственно на форуме, а не скопипастен из реального кода.

GRIG, нужен реальный код, а не похожий на него. Можно убрать оттуда куски, явно не относящиеся к делу, но пусть это будет тот самый код, что в одном случае работает, а в другом - нет.
 

GRIG

Новичок
Ну хорошо, давай так
PHP:
  $conditions = Array();
  $vallist = Array();
  $sql = "SELECT ,.. FROM ( SELECT C1, C2, COUNT(*) CNT ... FROM моя таблица ";
// Формулируем условия по фильтру
// Пользователь
  if( isset( $uinfo['opts']['author'] ) && $uinfo['opts']['author'] != '' && $uinfo['opts']['author'] != 'all' )
  {
    $conditions[] = 'CREATOR = :author';
    $vallist[':author'] = $uinfo['opts']['author'];
  }
//...
// Еще несколько аналогичных конструкций 
// ...
// Добавить часть WHERE
  if( count( $conditions ) > 0 )
  {
    $sql .= "WHERE " . implode( $conditions, ' AND ' );
  }
  $sql .=      " GROUP BY C1, C2 ), ...  WHERE ... ORDER BY ... ";
// исполняем запрос
  $stmt = ociparse( $conn, $sql );
  foreach( $vallist as $key => $val )
  {
    ocibindbyname( $stmt, $key, $vallist[$key]  );
// ocibindbyname( $stmt, $key, $val );
  }
  ociexecute( $stmt );
  $num = ocifetchstatement( $stmt, $result )
Вот так работает. А если внутри foreach перекинуть комментарий на другую строку - то работать перестанет.
 

Фанат

oncle terrible
Команда форума
во-первых, нужно пользоваться тегом
PHP:
во-вторых, что значит "перекинуть коммментарий" и в чем конкретно выражается "работать перестает"
 

Fortop

Новичок
Биндниг происходит на переменную (т.е. по ссылке), а не на значение.

Поэтому все значения что вы забиндили будут одинаковыми и равными последнему элементу.

Вот так должно работать
PHP:
foreach( $vallist as $key => &$val ) {
    ocibindbyname( $stmt, $key, $val );
}
 

GRIG

Новичок
Автор оригинала: *****
во-первых, нужно пользоваться тегом ...
во-вторых, что значит "перекинуть коммментарий" и в чем конкретно выражается "работать перестает"
Это значит примерно следующее. Если написано вот так:
PHP:
foreach( $vallist as $key => $val )
{
  ocibindbyname( $stmt, $key, $vallist[$key] );
}
то все работает нормально. А если вот так:
PHP:
foreach( $vallist as $key => $val )
{
 ocibindbyname( $stmt, $key, $val );
}
То читает не все, что есть в базе. Иногда даже может сказать "не найдено", хотя информация в базе есть.

-~{}~ 30.03.10 15:26:

Автор оригинала: Fortop
Биндниг происходит на переменную (т.е. по ссылке), а не на значение.

Поэтому все значения что вы забиндили будут одинаковыми и равными последнему элементу.

Вот так должно работать
PHP:
foreach( $vallist as $key => &$val ) {
    ocibindbyname( $stmt, $key, $val );
}
Вот как раз так и не работает :-(
Хотя насчет "биндинг по ссылке" - это надо подумать. Похоже, это действительно объяснение.
 

GRIG

Новичок
Автор оригинала: Fortop
Изучите внимательно разницу между Вашим и моим кодом
При внимательном рассмотрении заметил амперсанд, на который поначалу не обратил внимания. Картина потихоньку начинает проясняться.
 
Сверху