PHP - Змінення поточного об'єкта в циклі foreach


111

Мені було цікаво, чи можна редагувати поточний об’єкт, який обробляється в foreachциклі

Я працюю з масивом об'єктів, $questionsі я хочу пройти і шукати відповіді, пов'язані з цим об'єктом питання, в моєму db. Тож для кожного запитання знайдіть об’єкти відповідей та оновіть поточний $question всередині мого foreachциклу, щоб я міг виводити / обробляти в іншому місці.

foreach($questions as $question){
    $question['answers'] = $answers_model->get_answers_by_question_id($question['question_id']);
}

Як і Артьом Курапов, і @topener припустили, що я шукав "пройти через посилання", використовуючи знак &. Дякую хлопцям :) приємного дня
Гарбіт

Відповіді:


207

Є два способи зробити це

foreach($questions as $key => $question){
    $questions[$key]['answers'] = $answers_model->get_answers_by_question_id($question['question_id']);
}

Таким чином ви зберігаєте ключ, тож зможете оновити його ще раз у головній $questionsзмінній

або

foreach($questions as &$question){

Додавання &буде постійно $questionsоновлюватись. Але я б сказав, що перший рекомендується, навіть якщо це коротше (див. Коментар Paystey)

Відповідно до foreachдокументації PHP :

Щоб мати можливість безпосередньо змінювати елементи масиву в циклі, передує значення $ з &. У цьому випадку значення буде присвоєне посиланням.


32
Посилання в foreachсправді не рекомендується, так як foreachпроходження навколо ціннісної частини циклу призводить до непередбачуваної поведінки. Це може бути довше, але ви набагато безпечніше, використовуючи метод 1 тут.
Пейсті

1
Я щойно провів здивовану годину, налагоджуючи проблему, спричинену використанням посилання в передбаченні. Я повторно використовував те саме ім’я змінної для другого виклику foreach - коли я передав перший за посиланням, він продовжував змінювати останній елемент у масиві! Використання явного індексу не мало б цієї проблеми.
Hippyjim

7
@Paystey Ви можете навести свої джерела або дати детальне пояснення?
Ніко

2
Чому маніпулювання посиланнями було б небезпечно? Чи є C / C ++, де вам доведеться маніпулювати посиланнями скрізь небезпечно? Вам належить зробити це безпечним чи ні, не мовою.
Кальзем

2
@BabyAzerty: Paystey не сказали посилання "в загальному", але foreach, о жах , як це: stackoverflow.com/questions/3307409 / ... (@Nico, FYI, теж.)
Sz.

6

Безперечно, array_mapі якщо використовувати контейнер, що реалізує ArrayAccessдля отримання об'єктів, це просто розумніший, семантичний спосіб зробити це?

Семантика карт масиву схожа на більшості мов та реалізацій, які я бачив. Він призначений для повернення модифікованого масиву на основі елемента вхідного масиву (високий рівень ігнорування налаштування типу компіляції / типу виконання програми); цикл покликаний виконувати більше логіки.

Для отримання об'єктів за допомогою ID / PK, залежно від того, використовуєте ви SQL чи ні (здається, що пропонується), я б застосував фільтр, щоб переконатися, що я отримав масив дійсних ПК, а потім імплодую з комою та розміщую в IN()пункті SQL для повернути набір результатів. Здійснює один виклик замість кількох через SQL, оптимізуючи трохи call->waitциклу. Найголовніше, щоб мій код був добре прочитаний комусь із будь-якої мови з певним рівнем компетенції, і ми не стикаємося з проблемами змін.

<?php

$arr = [0,1,2,3,4];
$arr2 = array_map(function($value) { return is_int($value) ? $value*2 : $value; }, $arr);
var_dump($arr);
var_dump($arr2);

проти

<?php

$arr = [0,1,2,3,4];
foreach($arr as $i => $item) {
    $arr[$i] = is_int($item) ? $item * 2 : $item;
}
var_dump($arr);

Якщо ви знаєте, що ви робите, у вас ніколи не виникне проблем із зміною (маючи на увазі, якщо ви збираєтесь перезаписати, $arrви завжди могли $arr = array_mapбути чіткими та чіткими.


2
Набагато інтуїтивніше, ніж робити передбачення - саме для цього розрахована ця функція.
Бенджамінгул
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.