PHP - Sửa đổi đối tượng hiện tại trong vòng lặp foreach


111

Tôi đã tự hỏi liệu có thể chỉnh sửa đối tượng hiện tại đang được xử lý trong foreachvòng lặp không

Tôi đang làm việc với một mảng các đối tượng $questionsvà tôi muốn xem qua và tìm kiếm câu trả lời được liên kết với đối tượng câu hỏi đó trong db của tôi. Vì vậy, đối với mỗi câu hỏi, hãy tìm nạp các đối tượng trả lời và cập nhật hiện tại $question bên trongforeach vòng lặp của tôi để tôi có thể xuất / xử lý ở nơi khác.

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

Vì cả ArtjomKurapov và @topener đều gợi ý, tôi đang tìm kiếm 'chuyển qua tham chiếu' bằng cách sử dụng dấu &. Cảm ơn chaps :) có một ngày tốt đẹp
Garbit

Câu trả lời:


207

Có 2 cách để làm điều này

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

Bằng cách này, bạn lưu khóa, vì vậy bạn có thể cập nhật lại khóa trong $questionsbiến chính

hoặc là

foreach($questions as &$question){

Thêm ý &muốn giữ $questionscập nhật. Nhưng tôi sẽ nói rằng cái đầu tiên được đề xuất mặc dù cái này ngắn hơn (xem bình luận của Paystey)

Theo tài liệu PHPforeach :

Để có thể sửa đổi trực tiếp các phần tử mảng trong vòng lặp đặt trước giá trị $ bằng &. Trong trường hợp đó, giá trị sẽ được gán bằng tham chiếu.


32
Các tham chiếu trong foreachthực sự không được khuyến khích, cách các foreachđường chuyển xung quanh phần giá trị của vòng lặp dẫn đến hành vi không thể nhận ra. Nó có thể lâu hơn nhưng bạn an toàn hơn nhiều khi sử dụng phương pháp 1 ở đây.
Paystey

1
Tôi vừa trải qua một giờ bối rối để gỡ lỗi sự cố do sử dụng tham chiếu trong foreach. Tôi đã sử dụng lại cùng một tên biến cho lần gọi foreach thứ hai - vì tôi đã chuyển đầu tiên bằng cách tham chiếu, nó tiếp tục sửa đổi mục cuối cùng trong mảng! Sử dụng một chỉ mục rõ ràng sẽ không gặp vấn đề này.
Hippyjim

7
@Paystey bạn có thể trích dẫn nguồn của bạn hoặc giải thích chi tiết không?
Nico

2
Tại sao thao tác tham chiếu sẽ không an toàn? C / C ++ có phải là nơi bạn phải thao tác các tham chiếu ở mọi nơi không an toàn không? Việc làm cho nó an toàn hay không là tùy thuộc vào bạn, không phải ngôn ngữ.
Kalzem

2
@BabyAzerty: Paystey không nói các tài liệu tham khảo "nói chung", nhưng nói foreachvề kinh dị như thế này: stackoverflow.com/questions/3307409/… (@Nico, FYI, quá.)
Sz.

6

Chắc chắn việc sử dụng array_mapvà nếu sử dụng một container thực hiện ArrayAccessđể dẫn xuất các đối tượng chỉ là một cách thông minh hơn, về mặt ngữ nghĩa để thực hiện điều này?

Ngữ nghĩa của bản đồ mảng tương tự nhau trên hầu hết các ngôn ngữ và cách triển khai mà tôi đã thấy. Nó được thiết kế để trả về một mảng đã sửa đổi dựa trên phần tử mảng đầu vào (mức cao bỏ qua tùy chọn kiểu thời gian chạy / biên dịch ngôn ngữ); một vòng lặp có nghĩa là thực hiện nhiều logic hơn.

Để truy xuất các đối tượng bằng ID / PK, tùy thuộc vào việc bạn có đang sử dụng SQL hay không (có vẻ như được đề xuất), tôi sẽ sử dụng một bộ lọc để đảm bảo tôi nhận được một mảng các PK hợp lệ, sau đó mã hóa bằng dấu phẩy và đặt vào một IN()mệnh đề SQL để trả về tập hợp kết quả. Nó thực hiện một cuộc gọi thay vì nhiều cuộc gọi thông qua SQL, tối ưu hóa một chút call->waitchu trình. Quan trọng nhất là mã của tôi sẽ đọc tốt cho một người từ bất kỳ ngôn ngữ nào có năng lực và chúng tôi không gặp phải vấn đề về khả năng thay đổi.

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

Nếu bạn biết những gì bạn đang làm sẽ không bao giờ có vấn đề về khả năng thay đổi (hãy ghi nhớ nếu bạn có ý định ghi đè, $arrbạn luôn có thể $arr = array_mapvà rõ ràng.


2
Trực quan hơn nhiều so với thực hiện foreach - đây chính xác là những gì chức năng này được thiết kế cho.
benjaminhull
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.