Таким образом, $ array является массивом, из которого все элементы являются ссылками.
Я хочу добавить этот массив к другому массиву с именем $ results (в цикле), но поскольку они являются ссылками, PHP копирует ссылки, а $ results имеет одинаковые элементы.
На сегодняшний день лучшим рабочим решением является:
$results[] = unserialize(serialize($array));
который я боюсь быть невероятно неэффективным. Есть лучший способ сделать это?
Вы можете использовать тот факт, что при $array_by_myclone
возвращаются результаты функции $array_by_myclone
здесь $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, и оказалось, что это неправильно: использование метода сериализации медленнее даже с небольшим набором данных и тем больше данных у вас получается медленнее.
lepidosteus@server:~$ 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 lepidosteus@server:~$ php reference.php 1 myclone: 0.000010 seconds serialize: 0.000012 seconds lepidosteus@server:~$ 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);
нет необходимости сравнивать 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 не работает.