PHP - изменить текущий объект в цикле foreach


111

Мне было интересно, можно ли отредактировать текущий объект, который обрабатывается в foreachцикле

Я работаю с массивом объектов $questionsи хочу просмотреть и найти ответы, связанные с этим объектом вопроса, в моей базе данных. Итак, для каждого вопроса выберите объекты ответа и обновите текущий $question внутри моего foreachцикла, чтобы я мог выводить / обрабатывать где-нибудь еще.

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

Как и ArtjomKurapov, так и @topener предположили, что я искал «передать по ссылке», используя знак &. Спасибо, ребята :) хорошего дня
Гарбит

Ответы:


207

Есть 2 способа сделать это

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

Таким образом вы сохраните ключ, чтобы вы могли снова обновить его в основной $questionsпеременной

или

foreach($questions as &$question){

При добавлении &будет $questionsобновляться. Но я бы сказал, что рекомендуется первый, хотя он короче (см. Комментарий Пейстей)

Согласно документации PHPforeach :

Чтобы иметь возможность напрямую изменять элементы массива внутри цикла, перед значением $ value стоит &. В этом случае значение будет присвоено по ссылке.


32
Ссылки в foreachдействительно не рекомендуется, способ foreachпередачи части значения цикла приводит к непредсказуемому поведению. Это может быть дольше, но вы гораздо безопаснее использовать здесь метод 1.
Paystey

1
Я просто час в недоумении потратил на отладку проблемы, вызванной использованием ссылки в foreach. Я повторно использовал то же имя переменной для второго вызова foreach - поскольку я передал первую по ссылке, она продолжала изменять последний элемент в массиве! Использование явного индекса не привело бы к этой проблеме.
Hippyjim

7
@Paystey, можешь ли ты процитировать свои источники или дать подробное объяснение?
Нико

2
Почему манипулирование ссылками небезопасно? Является ли C / C ++, где вам приходится повсюду манипулировать ссылками, небезопасно? Делать это безопасно или нет - решать вам, а не языку.
Kalzem

2
@BabyAzerty: Пейстей не упоминал "в общем", но в foreachотношении ужасов вроде этого: stackoverflow.com/questions/3307409/… (@Nico, к сведению тоже)
Sz.

6

Разумеется, использование array_mapи если использование контейнера ArrayAccessдля получения объектов - это просто более разумный семантический способ сделать это?

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

Для извлечения объектов по ID / PK, в зависимости от того, используете ли вы SQL или нет (это кажется предложенным), я бы использовал фильтр, чтобы убедиться, что я получаю массив действительных PK, затем запятую и поместите в предложение SQL IN(), чтобы вернуть набор результатов. Он делает один вызов вместо нескольких через 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
Намного более интуитивно понятный, чем выполнение foreach - именно для этого и предназначена эта функция.
Benjaminhull
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.