Apakah ada fungsi untuk membuat salinan array PHP ke yang lain?


530

Apakah ada fungsi untuk membuat salinan array PHP ke yang lain?

Saya telah dibakar beberapa kali mencoba menyalin array PHP. Saya ingin menyalin array yang didefinisikan di dalam suatu objek ke global di luarnya.


benar-benar terlambat, tetapi di Lingkungan saya, saya menguji ini (dan berhasil): function arrayCopy (array $ a) {return $ a; } $ a1 = array (); for ($ i = 0; $ i <3; $ i ++) {$ a1 ["key- $ i"] = "nilai # $ i"; } $ a1 ["key-sub-array"] = array (1, 2, 3, 4); $ a2 = $ a1; $ a3 = arrayCopy ($ a1); for ($ i = 0; $ i <3; $ i ++) {if (! is_array ($ a2 ["key- $ i"])) {$ a2 ["key- $ i"] = "nilai yang diubah # $ saya"; }} $ a2 ["key-sub-array"] = array ("sub-array 1 diubah", "sub-array 2 diubah"); var_dump ($ a1); var_dump ($ a2); var_dump ($ a3); Caranya adalah, untuk tidak melewatkan array sebagai referensi ke fungsi ;-)
Sven

Jawaban:


927

Dalam array PHP ditugaskan oleh copy, sedangkan objek ditugaskan oleh referensi. Ini berarti:

$a = array();
$b = $a;
$b['foo'] = 42;
var_dump($a);

Akan menghasilkan:

array(0) {
}

Sedangkan:

$a = new StdClass();
$b = $a;
$b->foo = 42;
var_dump($a);

Hasil:

object(stdClass)#1 (1) {
  ["foo"]=>
  int(42)
}

Anda bisa bingung oleh seluk-beluk seperti ArrayObject, yang merupakan objek yang bertindak persis seperti sebuah array. Namun, sebagai objek, ia memiliki semantik referensi.

Sunting: @AndrewLarsson memunculkan poin dalam komentar di bawah. PHP memiliki fitur khusus yang disebut "referensi". Mereka agak mirip dengan pointer dalam bahasa seperti C / C ++, tetapi tidak persis sama. Jika array Anda berisi referensi, maka saat array itu sendiri dilewatkan oleh salinan, referensi masih akan menyelesaikan ke target asli. Itu tentu saja biasanya perilaku yang diinginkan, tetapi saya pikir itu layak disebutkan.


104
Anda tidak menjawab pertanyaan itu. Anda hanya menjelaskan masalahnya. Yang mana, untuk OP, kemungkinan besar adalah apa yang dia cari. Namun, bagi saya (dan yang lainnya juga), datang ke sini hampir empat tahun kemudian dengan masalah yang sama, saya masih belum memiliki cara yang baik untuk mengkloning array tanpa memodifikasi array asli (yang termasuk internal pointer juga). Saya kira sudah waktunya bagi saya untuk mengajukan pertanyaan saya sendiri.
Andrew Larsson

28
@AndrewLarsson Tapi PHP melakukan itu secara default - Itulah intinya. Referensi tidak diselesaikan, jadi jika Anda membutuhkannya, Anda harus secara traverse melintasi array dan membangun yang baru - Demikian pula, jika array sumber berisi objek, dan Anda ingin yang dikloning, Anda harus melakukannya secara manual. Perlu diingat juga bahwa referensi dalam PHP tidak sama dengan pointer dalam C. Tanpa mengetahui apa pun tentang kasus Anda, bolehkah saya menyarankan bahwa aneh untuk memiliki array referensi dalam kasus pertama, terutama jika Anda tidak berniat untuk memperlakukan mereka sebagai referensi? Apa gunanya?
troelskn

1
@troelskn Saya menambahkan jawaban untuk pertanyaan ini dengan solusi untuk masalah saya: stackoverflow.com/a/17729234/1134804
Andrew Larsson

3
Tapi bagaimana kalau perilaku yang tidak diinginkan? Pertanyaannya adalah bagaimana cara membuat salinan yang dalam . Jelas tidak diinginkan. Jawaban Anda adalah tidak lebih baik dari: $copy = $original;. Yang tidak berfungsi jika elemen array adalah referensi.
doug65536

8
Seperti selalu memberi phpkita hasil yang paling tidak diharapkan , karena solusi ini tidak selalu berhasil . $a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];mencetak array0sambil $a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];mencetak array1. Rupanya beberapa array disalin dengan referensi.
Tino

186

PHP akan menyalin array secara default. Referensi dalam PHP harus eksplisit.

$a = array(1,2);
$b = $a; // $b will be a different array
$c = &$a; // $c will be a reference to $a

Untuk menggunakan referensi mungkin penting jika array sangat besar. Saya tidak yakin tetapi saya menganggap itu harus mengarah pada konsumsi memori yang lebih sedikit dan kinerja yang lebih baik (tidak perlu menyalin seluruh array dalam memori).
robsch

11
@robsch - pada level logika program, array disalin. Tetapi dalam memori, itu tidak akan benar-benar disalin sampai dimodifikasi - karena PHP menggunakan semantik copy-on-write untuk semua jenis. stackoverflow.com/questions/11074970/…
Jessica Knight

@CoreyKnight Senang tahu. Terima kasih untuk ini.
robsch

4
perhatikan bahwa ini tidak benar untuk array bersarang, mereka adalah referensi dan Anda berakhir dengan kekacauan yang rusak
MightyPork

45

Jika Anda memiliki array yang berisi objek, Anda perlu membuat salinan array itu tanpa menyentuh pointer internal, dan Anda membutuhkan semua objek yang akan dikloning (sehingga Anda tidak mengubah aslinya ketika Anda membuat perubahan pada salinan array), gunakan ini.

Trik untuk tidak menyentuh pointer internal array adalah untuk memastikan Anda bekerja dengan salinan array, dan bukan array asli (atau referensi ke array), jadi menggunakan parameter fungsi akan menyelesaikan pekerjaan (dengan demikian, ini adalah fungsi yang mengambil array).

Perhatikan bahwa Anda masih perlu menerapkan __clone () pada objek Anda jika Anda ingin properti mereka juga dikloning.

Fungsi ini berfungsi untuk semua jenis array (termasuk tipe campuran).

function array_clone($array) {
    return array_map(function($element) {
        return ((is_array($element))
            ? array_clone($element)
            : ((is_object($element))
                ? clone $element
                : $element
            )
        );
    }, $array);
}

1
Perlu diingat bahwa ini adalah kasus khusus. Juga, perhatikan bahwa ini hanya akan mengkloning referensi tingkat pertama. Jika Anda memiliki array yang dalam, Anda tidak akan mendapatkan kloning yang lebih dalam, jika itu adalah referensi. Mungkin tidak menjadi masalah dalam kasus Anda, tetapi hanya perlu diingat.
troelskn

4
@troelskn Saya memperbaikinya dengan menambahkan beberapa rekursi. Fungsi ini sekarang akan berfungsi pada semua jenis array, termasuk tipe campuran. Ini juga berfungsi dengan baik untuk array sederhana, sehingga tidak dilokalkan lagi. Ini pada dasarnya mesin kloning array universal. Anda masih perlu mendefinisikan fungsi __clone () di objek Anda jika objek tersebut mendalam, tapi itu di luar "cakupan" fungsi ini (maaf untuk permainan kata-kata buruk).
Andrew Larsson

2
Saya sangat percaya ini adalah jawaban aktual untuk pertanyaan ini, Satu-satunya cara yang saya lihat untuk benar-benar menyalin sebuah array yang berisi objek.
Patrick

Itu tidak mengulangi properti objek yang mungkin memiliki array dan objek referensi lainnya.
ya.teck

6
Penggunaan kata __FUNCTION__ini brilian.
zessx

29

Saat kamu melakukan

$array_x = $array_y;

PHP menyalin array, jadi saya tidak yakin bagaimana Anda akan terbakar. Untuk kasus Anda,

global $foo;
$foo = $obj->bar;

harus bekerja dengan baik.

Agar terbakar, saya pikir Anda harus menggunakan referensi atau mengharapkan objek di dalam array yang akan dikloning.


12
+1 untuk ini: "atau mengharapkan objek di dalam array akan dikloning"
Melsi


18

sederhana dan membuat salinan dalam memecah semua tautan

$new=unserialize(serialize($old));

4
Secara umum itu berfungsi dengan baik namun dalam beberapa kasus mungkin mengeluarkan pengecualian karena tidak semua variabel serializable (misalnya penutupan dan koneksi database).
ya.teck

Hal lain yang perlu diperhatikan adalah referensi objek dapat dipulihkan jika kelas mengimplementasikan metode sihir __wakeup.
ya.teck

Terima kasih, akhirnya sesuatu yang benar-benar berfungsi, bukan jawaban bollock lainnya yang memiliki banyak upvotes, mereka pasti tidak berurusan dengan array objek seperti yang ditentukan dalam pertanyaan di mana jumlah elemen dalam array mungkin berubah, tetapi secara pasti bukan referensi ke benda di dalamnya
FentomX1

12

Saya suka array_replace(atau array_replace_recursive).

$cloned = array_replace([], $YOUR_ARRAY);

Ini berfungsi seperti Object.assigndari JavaScript.

$original = [ 'foo' => 'bar', 'fiz' => 'baz' ];

$cloned = array_replace([], $original);
$clonedWithReassignment = array_replace([], $original, ['foo' => 'changed']);
$clonedWithNewValues = array_replace([], $original, ['add' => 'new']);

$original['new'] = 'val';

akan menghasilkan

// original: 
{"foo":"bar","fiz":"baz","new":"val"}
// cloned:   
{"foo":"bar","fiz":"baz"}
// cloned with reassignment:
{"foo":"changed","fiz":"baz"}
// cloned with new values:
{"foo":"bar","fiz":"baz","add":"new"}

1
Bagaimana dengan array_slice($arr, 0)atau ketika Anda tidak peduli dengan kunci array_values($arr),? Saya pikir mereka mungkin lebih cepat daripada mencari dalam array. Juga, dalam javascript, ini cukup populer untuk digunakan Array.slice()untuk mengkloning array.
Christian

Di JS kita memiliki Object untuk pasangan kunci-nilai dan Array . PHP tidak membuat perbedaan ini. Untuk array PHP dengan indeks bernomor, array_slicedan semua metode lain yang disebutkan di sini berfungsi dengan sangat baik. Tetapi jika Anda ingin menggabungkan beberapa pasangan kunci-nilai (karena dimungkinkan juga dengan JS-Objects via Object.assignatau spread-syntax ), array_replacebisa lebih bermanfaat.
Putzi San

@Christian terima kasih atas sarannya array_values()yang bekerja sempurna untuk kasus penggunaan saya.
bigsee

11

Jika Anda hanya memiliki tipe dasar dalam array, Anda dapat melakukan ini:

$copy = json_decode( json_encode($array), true);

Anda tidak perlu memperbarui referensi secara manual.
Saya tahu itu tidak akan berhasil untuk semua orang, tetapi itu berhasil untuk saya


4
+1 ini adalah hal yang sangat buruk untuk dilakukan, tetapi secara teknis benar dan pintar. Jika saya melihat ini dalam kode saya akan menghadapi telapak tangan tetapi saya tidak bisa tidak menyukainya.
Reactgular

4

Karena ini tidak tercakup dalam salah satu jawaban dan sekarang tersedia di PHP 5.3 (diasumsikan Original Post menggunakan 5.2).

Untuk mempertahankan struktur array dan mengubah nilainya saya lebih suka menggunakan array_replaceatau array_replace_recursivetergantung pada kasus penggunaan saya.

http://php.net/manual/en/function.array-replace.php

Berikut adalah contoh menggunakan array_replacedan array_replace_recursivemenunjukkannya mampu mempertahankan urutan yang diindeks dan mampu menghapus referensi.

http://ideone.com/SzlBUZ

Kode di bawah ini ditulis menggunakan sintaks array pendek tersedia sejak PHP 5.4 yang menggantikan array()dengan []. http://php.net/manual/en/language.types.array.php

Berfungsi pada offset array yang diindeks dan nama yang diindeks

$o1 = new stdClass;
$a = 'd';
//This is the base array or the initial structure
$o1->ar1 = ['a', 'b', ['ca', 'cb']];
$o1->ar1[3] = & $a; //set 3rd offset to reference $a

//direct copy (not passed by reference)
$o1->ar2 = $o1->ar1; //alternatively array_replace($o1->ar1, []);
$o1->ar1[0] = 'z'; //set offset 0 of ar1 = z do not change ar2
$o1->ar1[3] = 'e'; //$a = e (changes value of 3rd offset to e in ar1 and ar2)

//copy and remove reference to 3rd offset of ar1 and change 2nd offset to a new array
$o1->ar3 = array_replace($o1->ar1, [2 => ['aa'], 3 => 'd']);

//maintain original array of the 2nd offset in ar1 and change the value at offset 0
//also remove reference of the 2nd offset
//note: offset 3 and 2 are transposed
$o1->ar4 = array_replace_recursive($o1->ar1, [3 => 'f', 2 => ['bb']]);

var_dump($o1);

Keluaran:

["ar1"]=>
  array(4) {
    [0]=>
    string(1) "z"
    [1]=>
    string(1) "b"
    [2]=>
    array(2) {
      [0]=>
      string(2) "ca"
      [1]=>
      string(2) "cb"
    }
    [3]=>
    &string(1) "e"
  }
  ["ar2"]=>
  array(4) {
    [0]=>
    string(1) "a"
    [1]=>
    string(1) "b"
    [2]=>
    array(2) {
      [0]=>
      string(2) "ca"
      [1]=>
      string(2) "cb"
    }
    [3]=>
    &string(1) "e"
  }
  ["ar3"]=>
  array(4) {
    [0]=>
    string(1) "z"
    [1]=>
    string(1) "b"
    [2]=>
    array(1) {
      [0]=>
      string(2) "aa"
    }
    [3]=>
    string(1) "d"
  }
  ["ar4"]=>
  array(4) {
    [0]=>
    string(1) "z"
    [1]=>
    string(1) "b"
    [2]=>
    array(2) {
      [0]=>
      string(2) "bb"
      [1]=>
      string(2) "cb"
    }
    [3]=>
    string(1) "f"
  }

3

Saya tahu ini sejak lama, tetapi ini berhasil untuk saya ..

$copied_array = array_slice($original_array,0,count($original_array));

2

Ini adalah cara saya menyalin array saya di Php:

function equal_array($arr){
  $ArrayObject = new ArrayObject($arr);
  return $ArrayObject->getArrayCopy();  
}

$test = array("aa","bb",3);
$test2 = equal_array($test);
print_r($test2);

Output ini:

Array
(
[0] => aa
[1] => bb
[2] => 3
)

2
Kenapa tidak bilang saja $test2 = $test;? Masalah apa yang ArrayObjectdipecahkan di sini?
Nate

1
<?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;
}
?>

1

Cara teraman dan termurah yang saya temukan adalah:

<?php 
$b = array_values($a);

Ini juga bermanfaat untuk mengindeks ulang array.

Ini tidak akan berfungsi seperti yang diharapkan pada array asosiatif (hash), tetapi tidak sebagian besar dari jawaban sebelumnya.


1

Membuat salinan ArrayObject

<?php
// Array of available fruits
$fruits = array("lemons" => 1, "oranges" => 4, "bananas" => 5, "apples" => 10);

$fruitsArrayObject = new ArrayObject($fruits);
$fruitsArrayObject['pears'] = 4;

// create a copy of the array
$copy = $fruitsArrayObject->getArrayCopy();
print_r($copy);

?>

dari https://www.php.net/manual/en/arrayobject.getarraycopy.php


0

Definisikan ini:

$copy = create_function('$a', 'return $a;');

Salin $ _ARRAY ke $ _ARRAY2:

$_ARRAY2 = array_map($copy, $_ARRAY);

0

Dalam array php, Anda hanya perlu menetapkannya ke variabel lain untuk mendapatkan salinan array itu. Tetapi pertama-tama Anda harus memastikan tentang jenisnya, apakah itu array atau arrayObject atau stdObject.

Untuk array php Sederhana:

$a = array(
'data' => 10
);

$b = $a;

var_dump($b);

output:

array:1 [
  "data" => 10
]

0
private function cloneObject($mixed)
{
    switch (true) {
        case is_object($mixed):
            return clone $mixed;
        case is_array($mixed):
            return array_map(array($this, __FUNCTION__), $mixed);
        default:
            return $mixed;
    }
}

0

$arr_one_copy = array_combine(array_keys($arr_one), $arr_one);

Cukup dengan memposting satu solusi lagi;)


-1
foreach($a as $key => $val) $b[$key] = $val ;

Mempertahankan kunci dan nilai. Array 'a' adalah salinan persis array 'b'

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.