Подтвердить что ты не робот

Глубокая копия массива ссылок PHP

Итак, $array - это массив, все элементы которого являются ссылками.

Я хочу добавить этот массив в другой массив, называемый $results (в цикле), но поскольку они являются ссылками, PHP копирует ссылки, а $results имеет одинаковые элементы.

До настоящего времени лучшим рабочим решением является:

$results[] = unserialize(serialize($array));

который я боюсь быть невероятно неэффективным. Есть ли лучший способ сделать это?

4b9b3361

Ответ 1

Вы можете использовать тот факт, что при возврате возникают результаты поиска функций, например здесь $array_by_myclone будет по-прежнему иметь ссылку на $original ($array_by_myclone[0][0] == 'foo'), а $array_by_assignment будет иметь клонированное значение ($array_by_assignment[0][0] == 'bar')

$original = 'foo';
$array_of_reference = array(&$original);

function myclone($value)
{
  return $value;
}

$array_by_myclone = array();
$array_by_myclone[] = array_map('myclone', $array_of_reference);

$array_by_assignment = array();
$array_by_assignment[] = $array_of_reference;

$original = 'bar';

var_dump($array_by_myclone[0][0]); // foo, values were cloned                                                                                                                                   
var_dump($array_by_assignment[0][0]); // bar, still a reference                     

EDIT: Я хотел проверить, был ли комментарий с выражением unserialize(serialize()) быстрее, поэтому я сделал тест с использованием php 5.5, и выясняется, что это неправильно: использование метода сериализации медленнее даже с небольшим набором данных и тем больше данных у вас будет медленнее.

[email protected]:~$ php -v
PHP 5.5.1-1~dotdeb.1 (cli) (built: Aug  3 2013 22:19:30) 
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2013 Zend Technologies
    with Zend OPcache v7.0.2-dev, Copyright (c) 1999-2013, by Zend Technologies
[email protected]:~$ php reference.php 1
myclone:   0.000010 seconds
serialize: 0.000012 seconds
[email protected]:~$ php reference.php 1000000
myclone:   0.398540 seconds
serialize: 0.706631 seconds

Используемый код:

<?php
$iterations = 1000000;
if (isset($argv[1]) && is_numeric($argv[1])) {
  $iterations = max(1, (int)$argv[1]);
}

$items = array();
for ($i = 0; $i < $iterations; $i++) {
  $items[] = 'item number '.$i;
}

$array_of_refs = array();
foreach ($items as $k => $v) {
  $array_of_refs[] = &$items[$k];
}

function myclone($value)
{
  return $value;
}

$start = microtime(true);

$copy = array_map('myclone', $array_of_refs);

$time = microtime(true) - $start;

printf("%-10s %2.6f seconds\n", 'myclone:', $time);

$start = microtime(true);

$copy = unserialize(serialize($array_of_refs));

$time = microtime(true) - $start;

printf("%-10s %2.6f seconds\n", 'serialize:', $time);

Ответ 2

нет необходимости сравнивать array_map с сериализацией. array_map не полезен.

$original = array('key'=>'foo');
$array_of_reference = array(&$original);
function myclone($value)
{
  return $value;
}
$array_by_myclone = array();
$array_by_myclone[] = array_map('myclone', $array_of_reference);

$array_by_assignment = array();
$array_by_assignment[] = $array_of_reference;

$original['key'] = 'bar';

var_dump($array_by_myclone[0][0]['key']); // bar, still a reference                                                                                                                                   
var_dump($array_by_assignment[0][0]['key']); // bar, still a reference   

array_map Применяет обратный вызов к элементам данных массивов, как и foreach. если массив, который вы хотите скопировать, имеет более одного гнезда, array_map не работает.