Изменение объекта в массиве изменяет значение сеанса

#php #laravel #laravel-7 #laravel-8

#php #ларавель #laravel-7 #laravel-8

Вопрос:

У меня есть следующий фрагмент кода в PHP Laravel, который содержит массив объектов. Каждый объект имеет 2 атрибута. Идентификатор и имя. Весь этот объект сохраняется в сеансе. Затем после сохранения я удаляю идентификатор из каждого объекта в массиве. Это также изменяет сеанс.

Я делаю что-то не так?

 $array = [];

$obj = new stdClass();
$obj->id = "1";
$obj->name = "Test";

array_push($array, $obj);

$request->session()->put('val', $array);

foreach($array as $key => $val) {
    unset($array[$key]->id);
}

echo "<pre>";
print_r($request->session()->get('val'));
echo "</pre>";
 

здесь я заметил, что атрибут id исчез из сеанса.

Комментарии:

1. Да, потому что вы редактируете одну и ту же копию массива.

2. @nice_dev — Не могли бы вы, пожалуйста, исправить код?

3. В чем смысл отмены установки? Вы хотите сохранить отдельные копии этого массива в сеансе, а также обычный массив?

4. @nice_dev: я отправляю новый массив в качестве ответа на интерфейс. Во внешнем интерфейсе атрибут id не нужен,

5. Полезны ли сеансы при использовании внешнего интерфейса и серверной части в 2 разных фреймворках?

Ответ №1:

Проблема возникает из-за того, что обрабатывается одна и та же копия объекта. Чтобы решить эту проблему, вам нужно clone будет создать объект, а затем отменить настройку и отправить в ответ, сохранив данные в сеансе нетронутыми.

 $cloned_data = [];
foreach($array as $key => $val) {
    $new_obj = clone $val;
    unset($new_obj->id);
    $cloned_data[] = $new_obj;
}

print_r($cloned_data);
 

Ответ №2:

Для отправки только имен во внешний интерфейс вы можете использовать collection pluck, чтобы получить новый массив только имен

 $dataForFrontend = collect($array)->pluck('name')->all();
 

Это изменяет представление данных для отправки во внешний интерфейс. [0] => ‘Тест’

Если вам нужно ввести его по имени — что-то вроде [0]['name'] => 'Test'

 $dataForFrontend = collect($data)->map(
    fn($item) => ['name' => $item->name]
)->all();
 

Если необходимо сохранить элементы массива как объекты исходного типа, по сути, такие же, как решение @nice_dev

 $dataForFrontend = collect($array)->map(function($item) {
    $clone = clone $item;
    unset($clone->id);

    return $clone;
})->all();
 

Сохранить элементы массива как объекты — не исходного типа, а как объекты std-класса

 $dataForFrontend = collect($data)->map(
    fn($item) => (object)['name' => $item->name]
)->all();
 

Комментарии:

1. Это изменяет представление данных для отправки во внешний интерфейс. [0] => 'Test'