Удаление элемента из объекта в цикле - PullRequest
5 голосов
/ 21 октября 2011

У меня есть набор результатов Db, которые хранятся в объекте.Мне нужно просмотреть результаты и проверить свойство (используя другой запрос к БД), а затем использовать оператор if, чтобы удалить элемент из объекта.Вот упрощенная версия того, что я пытаюсь сделать:

foreach ($products as $product) {

    if(!$product->active) {
        unset($product);
    }

}
print_r($products);

Однако, когда я печатаю_r, элементы все еще находятся в объекте.Я запутался.

Ответы [ 6 ]

12 голосов
/ 21 октября 2011

Это ожидаемое поведение.Есть два основных способа сделать то, что вы хотите

foreach ($products as $key => $product) {

    if(!$product->active) {
        unset($products[$key]);
    }

}

Второй способ будет использовать ссылка

foreach ($products as &$product) {

    if(!$product->active) {
        unset($product);
    }

}
3 голосов
/ 21 октября 2011

Вы должны понимать, что сброс объекта не влияет на php. Прежде всего, позвольте мне объяснить вам важную деталь с FOREACH:

если вы делаете:

$a = array(1,2,3,4,5);
foreach($a as $b){
    unset($b);
}

$ a будет сначала скопировано в память. Это не грубая копия, скажем так, она только копирует ссылку на данные и увеличивает количество использования массива (1,2,3,4,5) в памяти. Внутри $ b у вас будут копии данных, найденных в $ a. Следовательно, сброс его из памяти только говорит: эй, удалите $ b из копии $ a. Следовательно, не внося никаких изменений в реальные $ a.

Если бы вы сделали:

$a = array(1,2,3,4,5);
foreach($a as $key => $b){
    unset($a[$key]);
}

Тогда здесь у вас будет копия $ a в памяти. Foreach будет выполнять итерацию (цикл) для этой копии и предоставлять вам ключи для каждого элемента $ a, который копируется в $ b. Когда вы отменяете ($ a [$ key]), вы указываете php воздействовать на массив в $ a, который был скопирован при запуске foreach, но теперь, вместо того, чтобы воздействовать на копию, вы используете $ key для ссылки на элемент в $ a, который действительно существует в памяти и к которому у вас будет доступ.

Теперь для второй части, если мы посмотрим на объекты ... сброс объекта не имеет никакого эффекта, потому что переменные, содержащие объекты, являются только ссылками на данные в памяти со счетчиком. Если вы $ a = new Object () и затем $ b = $ a, вы создаете новую ссылку на этот объект, сохраняя его в целости и сохранности (не копируется).

Если бы вы сбросили ($ a), вы бы сбросили только ссылку на объект, а $ b все равно будет указывать на этот объект в памяти. Если вы сбрасываете ($ b), тогда вы сбрасываете ссылку на объект из памяти, потому что ничто не указывает на него.

Надеюсь, это прояснит ...

Удачи

2 голосов
/ 21 октября 2011

Используйте эту строку вместо:

foreach ($products as &$product)
1 голос
/ 21 октября 2011

Вы не можете сбросить саму переменную.Вам нужно использовать синтаксис foreach, который также дает ключ элемента, и использовать его для сброса ключа в массиве:

foreach ($products as $key => $product) {
    if(!$product->active) {
        unset($products[$key]);
    }
}
1 голос
/ 21 октября 2011

попробуйте это:

// $id is the key, $product is the value
foreach ($products as $id => $product) {
    if(!$product->active) {
        unset($products[$id]);
    }
}
0 голосов
/ 18 марта 2018

В качестве альтернативы, вы можете изменить цикл с использованием foreach и работать непосредственно с массивом, используя цикл for следующим образом:

<?php

$o1 = new stdClass;
$o2 = new stdClass;
$o3 = new stdClass;

$o1->active = false;
$o2->active = true;
$o3->active = true;


$products = [$o1, $o2, $o3];


for($i=0, $max=count($products); $i < $max; $i++) {
        if (!($products[$i]->active)) {
            unset($products[$i]);
        }
}
print_r($products);

// re-index:

$improvedProducts = array_values($products);
print_r($improvedProducts);

См. живой код .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...