PHP - Memodifikasi objek saat ini di foreach loop

111

Saya bertanya-tanya apakah mungkin untuk mengedit objek saat ini yang ditangani dalam satu foreachlingkaran

Saya bekerja dengan berbagai objek $questionsdan saya ingin menelusuri dan mencari jawaban yang terkait dengan objek pertanyaan di db saya. Jadi untuk setiap pertanyaan, ambil objek jawaban dan perbarui arus $question di dalam foreachloop saya sehingga saya dapat mengeluarkan / memproses di tempat lain.

foreach($questions as $question){
    $question['answers'] = $answers_model->get_answers_by_question_id($question['question_id']);
}
Garbit
sumber
Seperti yang disarankan ArtjomKurapov dan @topener, saya mencari 'referensi lewat' menggunakan tanda &. Terima kasih chaps :) semoga harimu menyenangkan
Garbit

Jawaban:

207

Ada 2 cara untuk melakukan ini

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

Dengan cara ini Anda menyimpan kunci, sehingga Anda dapat memperbaruinya lagi di $questionsvariabel utama

atau

foreach($questions as &$question){

Menambahkan &akan membuat $questionspembaruan tetap . Tetapi saya akan mengatakan yang pertama direkomendasikan meskipun ini lebih pendek (lihat komentar oleh Paystey)

Sesuai dokumentasi PHPforeach :

Untuk dapat secara langsung memodifikasi elemen array di dalam loop, awali $ value dengan &. Dalam hal ini, nilai akan diberikan sebagai referensi.

Rene Pot
sumber
32
Referensi dalam foreachbenar-benar tidak disarankan, cara foreachoperan di sekitar bagian nilai dari loop menghasilkan perilaku yang tidak dapat diprediksi. Mungkin lebih lama tetapi Anda jauh lebih aman menggunakan metode 1 di sini.
Paystey
1
Saya hanya menghabiskan waktu satu jam untuk men-debug masalah yang disebabkan oleh penggunaan referensi di foreach. Saya menggunakan kembali nama variabel yang sama untuk panggilan foreach kedua - karena saya telah melewati yang pertama dengan referensi, itu terus memodifikasi item terakhir dalam array! Menggunakan indeks eksplisit tidak akan menimbulkan masalah ini.
Hippyjim
7
@Paystey dapatkah Anda mengutip sumber Anda atau memberikan penjelasan mendetail?
Nico
2
Mengapa memanipulasi referensi tidak aman? Apakah C / C ++ tempat Anda harus memanipulasi referensi di mana pun tidak aman? Terserah Anda untuk membuatnya aman atau tidak, bukan bahasanya.
Kalzem
2
@BabyAzerty: Paystey tidak menyebutkan referensi "secara umum", tetapi foreachtentang horor seperti ini: stackoverflow.com/questions/3307409/… (@Nico, FYI, juga.)
Sz.
6

Tentunya menggunakan array_mapdan jika menggunakan wadah yang mengimplementasikan ArrayAccessuntuk mendapatkan objek hanyalah cara semantik yang lebih cerdas untuk melakukan hal ini?

Semantik peta larik serupa di sebagian besar bahasa dan implementasi yang pernah saya lihat. Ini dirancang untuk mengembalikan array yang dimodifikasi berdasarkan elemen array input (tingkat tinggi mengabaikan kompilasi bahasa / preferensi jenis runtime); loop dimaksudkan untuk melakukan lebih banyak logika.

Untuk mengambil objek dengan ID / PK, tergantung pada apakah Anda menggunakan SQL atau tidak (sepertinya disarankan), saya akan menggunakan filter untuk memastikan saya mendapatkan array PK yang valid, kemudian meledak dengan koma dan tempatkan ke IN()klausa SQL ke kembalikan set hasil. Itu membuat satu panggilan alih-alih beberapa melalui SQL, mengoptimalkan sedikit call->waitsiklus. Yang terpenting, kode saya akan terbaca dengan baik bagi seseorang dari bahasa apa pun dengan tingkat kompetensi tertentu dan kami tidak mengalami masalah mutabilitas.

<?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);

vs.

<?php

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

Jika Anda tahu apa yang Anda lakukan tidak akan pernah memiliki masalah mutabilitas (mengingat jika Anda berniat menimpa $arrAnda selalu bisa $arr = array_mapdan eksplisit.

MrMesees
sumber
2
Jauh lebih intuitif daripada melakukan foreach - untuk itulah fungsi ini dirancang.
benjaminhull