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;

Неточный ответ на вопрос ОП, но он помог мне и помог кому-то другому.