Получение ключа массива, соответствующего определенным критериям, работает только для нулевого ключа

#php #arrays #foreach

#php #массивы #foreach

Вопрос:

У меня есть этот цикл, который должен возвращать номер ключа, соответствующий определенным критериям (где md5 нескольких внутренних ключей соответствует строке, сообщаемой клиентом).

 foreach ( $response->posts as $key => $element ) {
    if ( $postData['sign'] == md5($api_secret.$postData['date'].$response->count.$element->text) ) {
        break;
    }
    elseif ( $postData['sign'] == md5($api_secret.$postData['date'].$postData['num'].$element->text) ) {
        $log_msg = date('H:i:s').' Comment "'.$postData['last_comment'].'" saved with less accuracy (another comment added before it was saved)';
        $this->wh_log($log_msg);
        break;
    }
    else {
        $log_msg = date('H:i:s').' Couldn't save the comment "'.$postData['last_comment'].'" sent from '.$ip.' because it failed the integrity check';
        $this->wh_log($log_msg);
        return $this->save_level2($access_token, $response, $referer);
    }
}
echo 'level 1 $key is '.$key.' || ';
  

Проблема в том, что во время дальнейшего тестирования выяснилось, что если он не находит условие соответствия в нулевом ключе ( $response->posts[0] ), то он немедленно переходит к последнему условию (определенному в else ) и создает файл журнала с ошибкой, даже не пытаясь найти условие соответствия в других ключах, таких как 1, 2 и т.д. И моя функция echo сообщает level 1 $key is 0 , в то время как предполагается, что она отображает ключ, который соответствует условию. Но, похоже, по какой-то причине это не выходит за пределы нулевого ключа.

// Я отредактировал код так, чтобы он не содержал переменных, которые люди не признали бы.

Комментарии:

1. В чем ошибка?

2. Кстати, в if и elseif echo 'level 1 $key is '.$key.' || '; это в не будет выполнено, так как это после break;

3. Нет проблем, сейчас это не проблема (но я отредактирую). Ошибки нет. Я просто не получаю правильный номер ключа. Он не проверяет другие ключи, кроме $response->posts[0] , на соответствие моим критериям.

4. Я попытаюсь объяснить лучше. Предполагается, что он возвращает номер подмассива, который содержит значения, md5 которых равен строке от клиента. Однако, если самый первый подмассив (т. е. $response->posts[0] ) не содержит таких значений, то он не проверяет другие подмассивы и немедленно выполняет условие, определенное в else , в то время как он должен выполняться только в том случае, если ни в одном массиве нет совпадающих значений (но такие значения есть в другом подмассиве, просто не в $response->posts[0] , а в $response->posts[1] ).

5. Кроме того, он всегда выдает эхо-сигнал level 1 $key is 0 , даже когда он должен был прерваться на другом ключе. P.S. Я допустил ошибку в этом примере, но я вернул положение функции echo туда, где оно было изначально (правильно).

Ответ №1:

Вы не перебираете значения ($elements)… Он всегда завершается после одной итерации:

  • Если условие номер один верно -> разорвет цикл = нет итерации.
  • Если верно второе условие -> разорвет цикл = нет итерации.
  • Если оба имеют значение false -> вернет = прерывает цикл и завершает работу функции = без итерации.

Я не уверен, что вы пытаетесь сделать — исходя из вашего вопроса, вы ожидаете, что итерация прервется, когда один из хэшей будет равен, в противном случае продолжайте итерацию -> Повторно подумайте об использовании этих разрывов и возврата, я думаю, вы хотите использовать что-то еще вроде CONTINUE .

Пример:

 //Consider this example inputs based on your question:
$secret = "bla";
$date = "00:00:0000";
$num  = 1;
$postData = [
    "example sign1" => md5($secret.$date."postdatahere with date"),
    "example sign2" => md5($secret.$num."postdatahere with num"),
    "date"  => $date,
    "num"   => $num
];
$posts = [
    "key1" => ["text" => "postdatahere with date"],
    "key2" => ["text" => "postdatahere with num"],
    "key3" => ["text" => "will exit the loop"]
];

//Run -> check_postdata is the function containing the logic:
echo check_postdata($posts, $postData, $secret, "example sign1")."n";
echo check_postdata($posts, $postData, $secret, "example sign2")."n";
  

Упрощенный пример 1 с использованием вашей методологии:

 //Using this logic with the BREAKs:
function check_postdata($posts, $postData, $secret, $example) {
    foreach ( $posts as $key => $element ) {

        //Same as the md5 part:
        $correct_value_date = md5($secret.$postData["date"].$element["text"]);
        $correct_value_num = md5($secret.$postData["num"].$element["text"]); 

        if ( $postData[$example] === $correct_value_date ) {
            echo "  -  ".$key." -> break in IF block!n";
            break;
        }
        elseif ( $postData[$example] === $correct_value_num ) {
            echo "  -  ".$key." -> break in ELSEIF block!n";
            break;
        } else {
            echo "  -  ".$key." -> continue in ELSE block!n";
            return 0;
        }

    }
    return 1;
}
/*  The Result is:
 *
 *  -  key1 -> break in IF block!
 *  1
 *  -  key1 -> continue in ELSE block!
 *  0
 */
  

Упрощенный пример 2 с использованием CONTINUE :

 //Using this logic with the CONTINUE:
function check_postdata($posts, $postData, $secret, $example) {
    foreach ( $posts as $key => $element ) {

        //Same as the md5 part:
        $correct_value_date = md5($secret.$postData["date"].$element["text"]);
        $correct_value_num = md5($secret.$postData["num"].$element["text"]); 

        if ( $postData[$example] === $correct_value_date ) {
            echo "  -  ".$key." -> break in IF block!n";
            break;
        }
        elseif ( $postData[$example] === $correct_value_num ) {
            echo "  -  ".$key." -> break in ELSEIF block!n";
            break;
        } else {
            echo "  -  ".$key." -> return in ELSE block!n";
            continue;
        }

    }
    return "Returned key is: ".$key;
}
/*  The Result is:
 *
 *    -  key1 -> break in IF block!
 *  Returned key is: key1
 *    -  key1 -> continue in ELSE block!
 *    -  key2 -> break in ELSEIF block!
 *  Returned key is: key2
 */
  

Как вы можете видеть, использование вашей логики не имеет смысла, поскольку она всегда будет повторяться один раз и останавливаться.
Использование CONTINUE метода будет повторяться до тех пор, пока одно из условий не будет выполнено.

Надеюсь, я помог..

Комментарии:

1. «Исходя из вашего вопроса, вы ожидаете, что итерация прервется, когда два сравниваемых хэша не совпадут » — на самом деле, это наоборот, то, что мне нужно. Я думал, что четко определил проблему … //Хотя я все еще читаю примеры.

2. Я изменил breaks на continue . Это ничего не изменило. Когда я ссылаюсь на $key after этого цикла, он всегда возвращает 0 , а не ключ, в котором он должен был прерваться. И он по-прежнему не прерывается после правильного ключа.

3. @ErikGordon Я отредактировал примеры -> посмотрите пример 2 (мое предложение) теперь он повторяется до тех пор, пока не будет найдена правильная первая запись…

4. Спасибо, но в него не вошла моя else часть (я не хотел продолжать else ), поэтому я написал свой собственный ответ, который полностью решает проблему. В любом случае спасибо за помощь.

Ответ №2:

Наконец-то решена проблема. Мне пришлось создать переменную, которая устанавливается только в том случае, если найдено совпадение. Кроме того, мне приходилось продолжать цикл каждый раз, когда совпадение не находилось. Я думал, что это будет продолжаться в любом случае, пока не будет выполнено условие, но я ошибался. Вот рабочее решение:

 foreach ( $response->posts as $key => $element ) {
    if ( $postData['sign'] == md5($api_secret.$postData['date'].$response->count.$element->text) ) {
        $key_obtained = $key;
        break;
    }
    else continue;
    if ( $postData['sign'] == md5($api_secret.$postData['date'].$postData['num'].$element->text) ) {
        $key_obtained = $key;
        $log_msg = date('H:i:s').' Comment "'.$postData['last_comment'].'" saved with less accuracy (another comment added before it was saved)';
        $this->wh_log($log_msg);
        break;
    }
    else continue;
    if ( !isset ($key_obtained) ) {
        $log_msg = date('H:i:s').' Couldn't save the comment "'.$postData['last_comment'].'" sent from '.$ip.' because it failed the integrity check';
        $this->wh_log($log_msg);
        return $this->save_level2($access_token, $response, $referer);
    }
}
echo 'level 1 $key is '.$key.' || ';
  

Комментарии:

1. вы знаете, что ваш второй ключ вообще никогда не вычисляется if ?

2. Честно говоря, я не специалист в области технологий, и у меня проблемы с пониманием логики программирования. Просто делаю хобби-проект. Поэтому, пожалуйста, скажите мне, как это исправить.

3. мой совет состоял бы в том, чтобы описать вашу проблему на подробном примере, который описывает то, что вы ищете. потому что, насколько я могу судить, ни одно из решений (включая мое) не отвечает на основную проблему, но фактически отвечает на некоторую интерпретацию вашего вопроса. итак, при описании ваших проблем обычно имеется несколько случаев, которые вы хотите обработать. попробуйте упростить свой пример, чтобы показать все случаи. например, «мой ввод — это список [1, 2, 3, 4], сначала я хочу проверить, есть ли 2, затем я хочу проверить, есть ли 4 впоследствии » или что-то в этом роде, по крайней мере, так я понимаю ваш ответ…

4. конечно, то, что ты не разбираешься в технологиях , усложняет задачу. обычно это помогает изложить ваши предположения о том, что должен делать ваш код (возможно, более подробно, в зависимости от вопросов, которые вы получаете в ответ, или если ответы не решают вашу проблему), и что он делает вместо этого. и это тем проще, чем больше вы упрощаете свою проблему. (некоторые люди зацикливаются на неправильных деталях)

Ответ №3:

во-первых, для корректности, ответ на исходный вопрос «почему рассматривается только первый ключ» (перефразированный) по-прежнему:

return немедленно завершит работу функции (если внутри функции) или скрипта / файла (в противном случае). и он будет возвращен независимо от того, находится он в цикле или нет. таким образом, при первом выполнении вашей else ветви цикл завершается из-за return , во всех других ветвях он завершается из-за break

однако для решения основной проблемы:

Проблема, которую нужно решить: найдите первый ключ, соответствующий условию 1, если его нет, найдите первый ключ, соответствующий условию 2, если его нет, выведите какой-нибудь общий материал (вывод ошибки).

Существует много способов решения этой проблемы, где основное различие заключается в том, выполняется ли цикл один или два раза. Поскольку вы уже определили свои условия, я просто назову их $cond1 и $cond2 соответственно:

 $cond1key = $cond2key = null; // <-- this stores what we'll find
foreach($response->posts as $key => $element) {
    if($cond1) {
         // if we find a key, for which $cond1 is true, we can abort
         $cond1key = $key;
         break;
    } elseif(!$cond2key amp;amp; $cond2) {
         // if we find a key, for which $cond2 is true, there still
         // may be a key, for which $cond1 is true, so no break.
         // also notice the !$cond2key in the if statement, this 
         // prevents overwriting
         $cond2key = $key;
    }
 }
 // now we look at the results of our "search"
 if($cond1key) {
     // key found by condition 1
     echo 'level 1 $key is '.$cond1key.' || ';
 } elseif($cond2key) {
     // key found by condition 2
     $log_msg = date('H:i:s').' Comment "'.$postData['last_comment'].'" saved with less accuracy (another comment added before it was saved)';
     $this->wh_log($log_msg);
 } else {
     // no key found
     $log_msg = date('H:i:s').' Couldn't save the comment "'.$postData['last_comment'].'" sent from '.$ip.' because it failed the integrity check';
     $this->wh_log($log_msg);
     return $this->save_level2($access_token, $response, $referer);
 }
  

теперь, я использовал там только один цикл, повторный цикл также был бы возможен (теперь код очень упрощен):

  foreach($response->posts as $key => $value) {
     if($cond1) {
          $cond1key = $key;
          break;
     }
 }
 if(!$cond1key) {
     foreach($response->posts as $key => $value) {
         if($cond2) { // no danger of overwriting, since we break ...
             $cond2key = $key;
             break; // since we're only looking for a cond2 key now.
         }
     }
 }
 // conditional code execution as before
  

Теперь этот код настолько прост, насколько я могу его сформулировать. Существуют несколько более элегантные решения, которые не дают реальной выгоды с точки зрения понимания, это абсолютно не предназначено для победы в каких-либо конкурсах;o)

Примечание: $cond1key / $cond2key явно неправильные имена, если у вас есть имена для этих переменных, которые семантически более подходят, используйте их.

Надеюсь, это поможет;o)

Комментарии:

1. Так и должно быть. Дело в том, что my else не должен выполняться в первую очередь. Потому что я точно знаю, что совпадающие значения присутствуют в другом ключе, просто не в [0] .

2. Позвольте мне попытаться объяснить еще более подробно… Если эта функция не находит совпадающих значений в $response->posts[0] , то она должна перебирать другие ключи, такие как $response->posts[1] , $response->posts[2] и т.д., пока не найдет совпадающие значения в некоторых из них. Затем он должен вернуть номер ключа, в котором совпадают значения. Но он никогда не выполняет итерацию по другим ключам… Таким образом, он может находить совпадающие значения только в $response->posts[0] и не проверяет другие ключи, даже если нулевой ключ не содержит совпадающих значений (если бы это было так, то это было бы ожидаемым поведением).

3. это именно то, что я сказал, это циклический просмотр сообщений, и этот цикл прекратится, как только встретится break or return , что так и есть, прямо при $key=0. нет распараллеливания или чего-либо еще.

4. Но my key 0 не соответствует if условию, так зачем же на нем останавливаться?

5. Предполагается, что он должен только прерываться if ( $postData['sign'] == md5($api_secret.$postData['date'].$response->count.$element->text) ) ; Но при ключе 0 это условие не выполняется. Только один из других ключей удовлетворяет этому условию. И все же он прерывается при нуле.