PHP foreach змінює вихідні значення масиву


143

Я дуже новачок у багатовимірних масивах, і це дуже довго переживає мене.

Мій масив такий:

$fields = array(
    "names" => array(
         "type"         => "text",
         "class"        => "name",
         "name"         => "name",
         "text_before"  => "name",
         "value"        => "",
         "required"     => true,
    )
)

Тоді я отримав функцію перевірки, чи заповнені ці входи, якщо вони потрібні.

function checkForm($fields){
    foreach($fields as $field){
        if($field['required'] && strlen($_POST[$field['name']]) <= 0){
            $fields[$field]['value'] = "Some error";
        }
    }
    return $fields;
}

Зараз моя проблема полягає в цій лінії

$fields[$field]['value'] = "Some error";

Я хочу змінити вміст вихідного масиву, оскільки я це повертаю, але як я можу отримати ім'я поточного масиву (імена в цьому прикладі) в циклі foreach?



1
Незалежно від того, наскільки ви нові (або раніше були) - це те, що ви можете прочитати з документації PHP: php.net/manual/en/control-structures.foreach.php
Микола Іванов

Відповіді:


261

У PHP, проходячи посиланням (& ) є ... суперечливим. Я рекомендую не використовувати його, якщо ви не знаєте, навіщо вам це потрібно, і перевірити результати.

Я рекомендую зробити наступне:

foreach ($fields as $key => $field) {
    if ($field['required'] && strlen($_POST[$field['name']]) <= 0) {
        $fields[$key]['value'] = "Some error";
    }
}

Тому в основному використовуйте, $fieldколи вам потрібні значення, і $fields[$key]коли вам потрібно змінити дані.


Приємно, це працює! Спробував щось подібне спочатку, але, мабуть, я накрутив якесь місце :) Зараз я використаю твій приклад тисячу разів і ніколи не забуду! :)
Jeppe

Радий, що це допомогло. Також рекомендую прочитати статтю, до якої я посилався , а також офіційну документацію для foreach ( php.net/manual/ro/control-structures.foreach.php )
Влад Преда

4
Підсумок: якщо ви збираєтеся змінити масив / змінну - тоді вам слід використовувати посилання. Це швидше, чистіше і читабельніше.
Лулу

2
Мені цікаво, чому проходження посилань на a foreachмає бути суперечливим? Це не так, як це функціональний виклик із прихованими побічними ефектами чи будь-чим іншим.
UncaAlby

1
Дякую за те, що ви сказали, що "проходження посилання (&) - це ... суперечливе", а не "не пройти посилання" або "пройти посилання - це зло". Менш вірогідний початок полум'яної війни. :)
Шон Бін

163

Використання &:

foreach($arr as &$value)
{
     $value = $newVal;
}

&передає значення масиву як посилання і не створює новий примірник змінної. Таким чином, якщо ви зміните посилання, початкове значення зміниться.

http://php.net/manual/en/language.references.pass.php

Редагувати 2018
Цю відповідь, здається, віддають перевагу багато людей в Інтернеті, саме тому я вирішив додати більше інформації та слова обережності.
Хоча прохід за посиланням у foreach(або функціях) - це чисте і коротке рішення, для багатьох новачків це може бути небезпечною проблемою.

  1. Петлі в PHP не мають власної області застосування. - @ Марк Амери

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

  2. Оскільки foreach покладається на внутрішній покажчик масиву в PHP 5, зміна його в циклі може призвести до несподіваної поведінки. - Документи PHP для foreach

    Видалення запису або зміна хеш-значення (ключа) під час ітерації в одному циклі може призвести до потенційно несподіваних поведінок в PHP <7. Проблема стає ще більш складною, коли сам масив є посиланням.

  3. Випереджайте результативність.
    Як правило, PHP віддає перевагу передачі за значенням завдяки функції копіювання при записі. Це означає, що внутрішньо PHP не створить копії даних, якщо їх копію не потрібно буде змінити. Дискусійно, чи foreachзапропонував би посилання на посилання вдосконалити ефективність роботи. Як це завжди, вам потрібно протестувати свій конкретний сценарій і визначити, який варіант використовує менше пам'яті та процесорного часу. Для отримання додаткової інформації дивіться публікацію SO, яку посилається NikiC нижче.

  4. Читання коду.
    Створення посилань у PHP - це те, що швидко виходить з рук. Якщо ви новачок і не маєте повного контролю над тим, чим займаєтесь, краще триматися подалі від посилань. Для отримання додаткової інформації про &оператора ознайомтеся з цим посібником: Довідка - Що означає цей символ у PHP?
    Для тих, хто хоче дізнатися більше про цю частину мови PHP : Пояснення посилань на PHP

Дуже приємне технічне пояснення @NikiC внутрішньої логіки циклів передбачення PHP :
Як насправді працює PHP 'foreach'?


Окрім перерахованих проблем, я рекомендую додавати unset($value);після foreachзакриття дужки, щоб переконатися, що змінна посилання вже не доступна після ітерації. 3v4l.org/2V2AQ
fyrye

15

Використовуйте foreach($fields as &$field){- значить, ви будете працювати з оригінальним масивом.

Ось докладніше про проходження посилання.


@RBA, будь ласка, посилайтесь на відповіді вище - вони мають набагато більше подробиць та оновлень - я не використовую php вже деякий час, тому не
знаю

1
function checkForm(& $fields){
    foreach($fields as $field){
        if($field['required'] && strlen($_POST[$field['name']]) <= 0){
            $fields[$field]['value'] = "Some error";
        }
    }
    return $fields;
}

Це те, що я б запропонував пройти за посиланням


Ця методика використовується для зміни значення вихідної змінної. оскільки PHP підтримує техніку Pass by Value Technique. Нам потрібно додати символ "&" перед змінною, щоб вказати це значення для передачі посилання
Sagar Kadam

1
Тоді навіщо все-таки повертатися $fields?
MAZux

Це найгірша відповідь із трьох запропонованих. Для того, хто натрапляє на цю відповідь, будь ласка, не розробляйте свої функції змінювати дані на місці та повертати їх. Для оригінального автора: Ви не надали жодних пояснень, чому це рішення було б краще, ніж інші, або як воно взагалі працює ..
Dharman

-6

Спробуйте це

function checkForm($fields){
        foreach($fields as $field){
            if($field['required'] && strlen($_POST[$field['name']]) <= 0){
                $field['value'] = "Some error";
            }
        }
        return $field;
    }

3
Не роби цього. Я можу бачити щонайменше дві речі неправильно з вашим кодом: присвоєння $ полі не працює (масив $ полів ніколи не змінюється, коли ви це робите), а return $ field повертає сингулярне поле, а не масив.
Staplerfahrer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.