PHP - Zmodyfikuj bieżący obiekt w pętli foreach


111

Zastanawiałem się, czy można edytować bieżący obiekt, który jest obsługiwany w foreachpętli

Pracuję z tablicą obiektów $questionsi chcę przejrzeć i poszukać odpowiedzi związanych z tym obiektem pytania w mojej bazie danych. Więc dla każdego pytania pobierz obiekty odpowiedzi i zaktualizuj prąd $question wewnątrz mojej foreachpętli, aby móc wyprowadzać / przetwarzać gdzie indziej.

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

Jak zasugerowali ArtjomKurapov i @topener, szukałem hasła „pass by reference” przy użyciu znaku &. Dzięki chłopaki :)
życzę

Odpowiedzi:


207

Można to zrobić na dwa sposoby

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

W ten sposób zapiszesz klucz, aby móc go ponownie zaktualizować w głównej $questionszmiennej

lub

foreach($questions as &$question){

Dodanie &będzie utrzymywać $questionsaktualizację. Ale powiedziałbym, że pierwszy jest zalecany, chociaż jest krótszy (patrz komentarz Paystey)

Zgodnie z foreachdokumentacją PHP :

Aby móc bezpośrednio modyfikować elementy tablicy w pętli, poprzedź $ wartość znakiem &. W takim przypadku wartość zostanie przypisana przez odniesienie.


32
Odniesienia w foreachnaprawdę nie są zalecane, ponieważ sposób, w jaki foreachprzechodzi wokół wartościowej części pętli, powoduje nieprzewidywalne zachowanie. Może to trwać dłużej, ale jesteś o wiele bezpieczniejszy przy użyciu metody 1 tutaj.
Paystey

1
Właśnie spędziłem kłopotliwą godzinę na debugowaniu problemu spowodowanego użyciem odwołania w foreach. Ponownie użyłem tej samej nazwy zmiennej dla drugiego wywołania foreach - ponieważ przekazałem pierwszą przez referencję, modyfikowała ona ostatnią pozycję w tablicy! Użycie jawnego indeksu nie spowodowałoby tego problemu.
Hippyjim,

7
@Paystey Czy możesz przytoczyć swoje źródła lub podać szczegółowe wyjaśnienie?
Nico

2
Dlaczego manipulowanie odniesieniami miałoby być niebezpieczne? Czy C / C ++, w którym musisz manipulować referencjami wszędzie, jest niebezpieczna? To od Ciebie zależy, czy będziesz bezpieczny, czy nie, a nie język.
Kalzem,

2
@BabyAzerty: Paystey nie mówił o odniesieniach „ogólnie”, ale w foreachodniesieniu do horroru: stackoverflow.com/questions/3307409/ ... (@Nico, FYI też.)
Sz.

6

Z pewnością używając array_mapi jeśli korzystasz z implementacji konteneraArrayAccess do wyprowadzania obiektów jest po prostu mądrzejszym, semantycznym sposobem rozwiązania tego problemu?

Semantyka mapy tablicowej jest podobna w większości języków i implementacji, które widziałem. Jest przeznaczony do zwracania zmodyfikowanej tablicy na podstawie elementu tablicy wejściowej (wysoki poziom ignorowania preferencji typu kompilacja / środowisko wykonawcze języka); pętla ma na celu wykonanie większej logiki.

Do pobierania obiektów według identyfikatora / PK, w zależności od tego, czy używasz SQL, czy nie (wydaje się to sugerowane), użyłbym filtra, aby upewnić się, że otrzymam tablicę prawidłowych PK, a następnie implodowałbym przecinkiem i umieścił w IN()klauzuli SQL , aby zwraca zestaw wyników. Wykonuje jedno wywołanie zamiast kilku za pośrednictwem SQL, optymalizując część call->waitcyklu. Co najważniejsze, mój kod dobrze czyta się komuś z dowolnego języka z pewnym stopniem kompetencji i nie mamy problemów ze zmiennością.

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

Jeśli wiesz, co robisz, nigdy nie będziesz mieć problemów ze zmiennością (pamiętaj, że jeśli zamierzasz nadpisać, $arrmożesz zawsze $arr = array_mapi wyraźnie powiedzieć.


2
O wiele bardziej intuicyjna niż robienie foreach - właśnie do tego została zaprojektowana ta funkcja.
benjaminhull
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.