Php копирование элементов массива по значению, а не по ссылке
У меня есть следующий код:
$data['x'] = $this->x->getResults();
$data['y'] = $data['x'];
//some code here to modify $data['y']
//this causes (undesirably) $data['x] to be modified as well
Я думаю, поскольку все элементы $data сами являются ссылками, модификация $data ['y'] также модифицирует $data ['x'].., который НЕ является тем, что я хочу. Я хочу, чтобы $data ['x'] оставался прежним. Есть ли способ разыменовать элементы здесь, чтобы я мог копировать элементы по значению?
Спасибо.
Обновление: $this- > x- > getResults(); возвращает массив объектов. Поэтому я могу сделать что-то вроде: $data ['x'] [0] → date_create...
Обновление:
моя последняя попытка клонировать массив выглядит примерно так:
$data['x'] = $this->x->getResults();
$data['y'] = $data['y'];
foreach($data['x'] as $key=>$row) {
$data['y'][$key]->some_attr = clone $row->some_attr;
}
Неужели я здесь? Я продолжаю получать ошибку "__clone метод, вызванный не-объектной" ошибкой. От чтения ответов кажется, что мой лучший вариант - перебрать каждый элемент и клонировать его (это то, что я пытался сделать с этим кодом..).
UPDATE: просто решил!: внутри цикла foreach мне просто нужно было изменить строку:
$data['y'][$key] = clone $row;
И это работает! Спасибо всем за помощь.
Ответы
Ответ 1
Вы можете воспользоваться тем фактом, что PHP будет разыменовывать результаты вызова функции.
Вот пример кода, который я взбивал:
$x = 'x';
$y = 'y';
$arr = array(&$x,&$y);
print_r($arr);
echo "<br/>";
$arr2 = $arr;
$arr2[0] = 'zzz';
print_r($arr);
print_r($arr2);
echo "<br/>";
$arr2 = array_flip(array_flip($arr));
$arr2[0] = '123';
print_r($arr);
print_r($arr2);
Результаты выглядят так:
Array ( [0] => x [1] => y )
Array ( [0] => zzz [1] => y ) Array ( [0] => zzz [1] => y )
Array ( [0] => zzz [1] => y ) Array ( [0] => 123 [1] => y )
Вы можете видеть, что результаты использования array_flip()
при выборе $arr
- $arr2
приводят к различиям в последующих изменениях в $arr2
, поскольку вызовы array_flip()
заставляют разыменовывать.
Это не выглядит ужасно эффективным, но это может сработать для вас, если $this->x->getResults()
возвращает массив:
$data['x'] = array_flip(array_flip($this->x->getResults()));
$data['y'] = $data['x'];
См. этот (неотвеченный) поток для другого примера.
Если все в вашем возвращенном массиве является объектом, однако, единственный способ скопировать объект - использовать clone()
, и вам нужно будет проходить через $data['x']
и клонировать каждый элемент в $data['y']
.
Пример:
$data['x'] = $this->x->getResults();
$data['y'] = array();
foreach($data['x'] as $key => $obj) {
$data['y'][$key] = clone $obj;
}
Ответ 2
array_flip()
не будет работать, если значения массива не являются строками или целыми числами.
Однако я нашел простое решение:
$clonedArr = (array)clone(object)$arr;
Это работает благодаря свойствам клона на объекте.
Ответ 3
Не просто.
Читайте о clone
НО! если ваши элементы не объекты и не являются переменными типа refence, у вас нет проблем.
Пример для ссылочных типов:
$v=11;
$arr[]=&$v;
Ответ 4
Если вы работаете с объектами, вы можете взглянуть на clone
, чтобы создать копию объекта вместо ссылки.
Вот очень короткий пример:
Сначала, с массивом, он работает по значению:
$data['x'] = array(
'a' => 'test',
'b' => 'glop',
);
$data['y'] = $data['x'];
$data['y'][0] = 'Hello, world!';
var_dump($data['x']); // a => test : no problem with arrays
По умолчанию, с объектами, он работает по ссылке:
$data['x'] = (object)array(
'a' => 'test',
'b' => 'glop',
);
$data['y'] = $data['x'];
$data['y']->a = 'Hello, world!';
var_dump($data['x']); // a => Hello, world! : objects are by ref
Но если вы клонируете объект, вы работаете над копией:
Я думаю, это ваш случай?
$data['x'] = (object)array(
'a' => 'test',
'b' => 'glop',
);
$data['y'] = clone $data['x'];
$data['y']->a = 'Hello, world!';
var_dump($data['x']); // a => test : no ref, because of cloning
Надеюсь, что это поможет,
Ответ 5
Вы можете использовать эту функцию для копирования многомерных массивов, содержащих объекты.
<?php
function arrayCopy( array $array ) {
$result = array();
foreach( $array as $key => $val ) {
if( is_array( $val ) ) {
$result[$key] = arrayCopy( $val );
} elseif ( is_object( $val ) ) {
$result[$key] = clone $val;
} else {
$result[$key] = $val;
}
}
return $result;
}
?>
Ответ 6
Я только что обнаружил, что если вы просто хотите получить копию массива значений (без ссылок) из константы, вы можете просто написать:
$new_array = (массив) (объект) self:: old_array;
Неточный ответ на вопрос ОП, но он помог мне и помог кому-то другому.