PHP dizisinin bir kopyasını diğerine kopyalamanın bir işlevi var mı?


529

PHP dizisinin bir kopyasını diğerine kopyalamanın bir işlevi var mı?

PHP dizilerini kopyalamaya çalışırken birkaç kez yandım. Bir nesnenin içinde tanımlanan bir diziyi onun dışında bir global kopyalamak istiyorum.


gerçekten geç, ama benim Ortamda bunu test (ve işe yaradı): function arrayCopy (array $ a) {return $ a; } $ a1 = dizi (); for ($ i = 0; $ i <3; $ i ++) {$ a1 ["key- $ i"] = "değer # $ i"; } $ a1 ["anahtar-alt dizisi"] = dizi (1, 2, 3, 4); $ a2 = $ a1; $ a3 = arrayCopy ($ a1); for ($ i = 0; $ i <3; $ i ++) {if (! is_array ($ a2 ["key- $ i"])) {$ a2 ["key- $ i"] = "# $ değerini değiştirdi ben"; }} $ a2 ["key-sub-array"] = dizi ("alt dizi 1 değiştirildi", "alt dizi 2 değiştirildi"); var_dump ($ a-1); var_dump ($ a2); var_dump ($ a3); İşin püf noktası, diziyi işleve bir referans olarak geçirmemek ;-)
Sven

Yanıtlar:


926

PHP dizilerinde kopya ile, nesneler referansla atanır. Bunun anlamı şudur ki:

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

Verim olacak:

array(0) {
}

Buna karşılık:

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

Verim:

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

ArrayObjectTam olarak bir dizi gibi davranan bir nesne gibi karmaşıklıklardan kafanız karışabilir . Ancak bir nesne olarak referans semantiği vardır.

Düzenleme: @AndrewLarsson aşağıdaki yorumlarda bir noktaya değiniyor. PHP'nin "referanslar" adı verilen özel bir özelliği vardır. C / C ++ gibi dillerdeki göstergelere biraz benziyorlar, ama aynı değiller. Diziniz referans içeriyorsa, dizinin kendisi kopya yoluyla geçirilirken, başvurular yine de orijinal hedefe çözümlenir. Tabii ki genellikle istenen davranış, ama bahsetmeye değer olduğunu düşündüm.


104
Soruya cevap vermedin. Sadece sorunu açıkladın. OP için büyük olasılıkla aradığı şey budur. Ancak, benim için (ve diğerleri de), neredeyse dört yıl sonra benzer bir problemle buraya geliyorum, hala orijinal diziyi değiştirmeden bir diziyi klonlamak için iyi bir yolum yok (iç göstergeleri de içeriyor). Sanırım kendi sorumu sorma zamanı geldi.
Andrew Larsson

28
@AndrewLarsson Ama PHP bunu varsayılan olarak yapıyor - Bu onun özü. Başvurular yine de çözülmez, bu yüzden buna ihtiyacınız varsa, diziyi tekrar tekrar dolaşmanız ve yeni bir tane oluşturmanız gerekir. PHP'deki referansların C'deki işaretçilerle aynı olmadığını da unutmayın . Durumunuz hakkında hiçbir şey bilmeden, özellikle tedavi etmek istemiyorsanız, ilk durumda bir dizi referansa sahip olmanın garip olduğunu önerebilir miyim? referans olarak? Kullanım durumu nedir?
troelskn

1
@troelskn Sorunuma bir çözüm ile bu soruya bir cevap ekledim: stackoverflow.com/a/17729234/1134804
Andrew Larsson

3
Peki ya istenen davranış olmadığında? Soru, nasıl derin bir kopya yapılacağını soruyor . Açıkçası istenmiyor. Cevabınız hayır daha iyi olduğunu: $copy = $original;. Dizi öğeleri başvuru ise hangisi işe yaramaz.
doug65536

8
Her zaman olduğu gibi phpbize en az beklenen sonucu veriyor , çünkü bu çözüm her zaman işe yaramıyor . $a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];baskılar array0ise $a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];baskılar array1. Görünüşe göre bazı diziler referans olarak kopyalanmıştır.
Tino

186

PHP diziyi varsayılan olarak kopyalar. PHP'deki referanslar açık olmalıdır.

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

Dizi çok büyükse, başvuruyu kullanmak önemli olabilir. Emin değilim ama daha az bellek tüketimi ve daha iyi performans (bellekte tüm dizi kopyalamak gerek) yol açacaktır varsayıyorum.
robsch

11
@robsch - program mantığı düzeyinde dizi kopyalanır. Ancak bellekte, değiştirilene kadar kopyalanmayacaktır - çünkü PHP tüm türler için yazma üzerine yazma anlambilimi kullanır. stackoverflow.com/questions/11074970/…
Jessica Knight

@CoreyKnight Bilmek güzel. Bunun için teşekkür ederim.
robsch

4
bu iç içe diziler için doğru olmadığını unutmayın, onlar referanslar ve böylece kırık bir karmaşa ile bitirmek
MightyPork

45

Nesneler içeren bir diziniz varsa, dahili işaretçisine dokunmadan bu dizinin bir kopyasını oluşturmanız ve tüm nesnelerin klonlanması gerekir (böylece kopyalananlarda değişiklik yaptığınızda orijinalleri değiştirmezsiniz) dizi), bunu kullanın.

Dizinin dahili işaretçisine dokunmamanın hilesi, dizinin bir kopyasıyla çalıştığınızdan emin olmaktır, orijinal diziyle (veya referansla) değil, bu nedenle bir işlev parametresi kullanmak işi bitirir (böylece, bu, bir diziyi alan bir işlevdir).

Özelliklerinin de klonlanmasını istiyorsanız, nesnelerinize __clone () uygulamanız gerektiğini unutmayın .

Bu işlev her tür dizi için çalışır (karışık tip dahil).

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

1
Bunun biraz özel bir durum olduğunu unutmayın. Ayrıca, bunun yalnızca birinci düzey referansları klonlayacağını unutmayın. Derin bir diziniz varsa, daha derin düğümlerin klonlanmasını sağlamazsınız. Durumunuzda bir sorun olmayabilir, ancak bunu aklınızda bulundurun.
troelskn

4
@troelskn Bazı özyineleme ekleyerek düzelttim. Bu işlev artık karışık türler de dahil olmak üzere herhangi bir dizi türü üzerinde çalışacaktır. Ayrıca basit diziler için de iyi çalışır, bu yüzden artık yerelleştirilmez. Temelde evrensel bir dizi klonlama makinesidir. Nesneleriniz derinse __clone () işlevini tanımlamanız gerekir, ancak bu bu işlevin "kapsamının" ötesindedir (kötü punto için özür dilerim).
Andrew Larsson

2
Bu sorunun gerçek cevabı olduğuna inanıyorum, Nesneleri içeren bir diziyi derinlemesine kopyalamak için gördüğüm tek yol.
Patrick

Başka dizilere ve başvurulan nesnelere sahip olabilecek nesne özelliklerini yinelemez.
17'de

6
Bu kullanımı __FUNCTION__mükemmel.
17'de zessx

29

Ne zaman yaparsın

$array_x = $array_y;

PHP dizi kopyalar, bu yüzden nasıl yanmış olurdu emin değilim. Davanız için,

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

iyi çalışmalı.

Yakılmak için ya referans kullanmanız ya da dizilerin içindeki klonlanmayı beklemeniz gerektiğini düşünürdüm.


12
Bunun için +1: "veya diziler içindeki nesnelerin klonlanmasını bekliyor"
Melsi


18

basit ve tüm bağlantıları koparmak derin kopya yapar

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

4
Genel olarak iyi çalışır, ancak bazı durumlarda istisna atabilir çünkü tüm değişkenler serileştirilemez (örneğin, kapanışlar ve veritabanı bağlantıları).
ya.teck

Dikkat edilmesi gereken başka bir şey, bir sınıf __wakeup magic yöntemini uygularsa nesne referanslarının geri yüklenebileceğidir.
ya.teck

Teşekkürler, nihayet gerçekten işe yarayan bir şey, diğer bollock cevapları bir sürü upvotes sahip değil, kesinlikle dizideki öğe sayısının değişebileceği söz konusu olarak belirtildiği gibi nesne dizisiyle uğraşmadılar, ancak içindeki nesneler
FentomX1

12

Seviyorum array_replace(veya array_replace_recursive).

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

Object.assignJavaScript gibi çalışır .

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

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

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

sonuçlanacak

// 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
Peki array_slice($arr, 0)ya anahtarlar umurunda değilken array_values($arr)? Ben bir dizide arama daha hızlı olabilir düşünüyorum. Ayrıca, javascript'te, Array.slice()dizileri klonlamak için oldukça popülerdir .
Christian

JS'de anahtar / değer çiftleri ve Array için Object var . PHP bu farkı yaratmaz. Numaralı dizinleri olan PHP dizileri için ve burada belirtilen diğer tüm yöntemler çok iyi çalışır. Ancak, birkaç anahtar / değer çiftini birleştirmek istiyorsanız (üzerinden JS-Objects veya spread-sözdizimi ile de mümkün olduğu gibi ), daha yararlı olabilir. array_sliceObject.assignarray_replace
Putzi San

@Christian, array_values()kullanım durumum için mükemmel çalışan önerisi için teşekkür ederim .
bigsee

11

Dizinizde yalnızca temel türler varsa bunu yapabilirsiniz:

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

Referansları manuel olarak güncellemenize gerek yok
Biliyorum, herkes için işe yaramayacak, ama benim için çalıştı


4
+1 bu gerçekten kötü bir şey, ama teknik olarak doğru ve akıllı. Eğer kodda bu gördüm ben palmiye karşı karşıya ama yardım edemem ama sevdim.
Reactgular

4

Bu, cevapların hiçbirinde ele alınmadığı ve şimdi PHP 5.3'te mevcut olduğu için (Original Post'un 5.2 kullandığı varsayılmıştır).

Bir dizi yapısını korumak ve değerlerini değiştirmek için kullanmayı array_replaceveya kullanım durumuma array_replace_recursivebağlı olarak kullanmayı tercih ederim .

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

Dizine alınmış sıralamayı koruyabildiğini ve bir referansı kaldırabildiğini gösteren array_replaceve array_replace_recursivegösteren bir örnek .

http://ideone.com/SzlBUZ

Aşağıdaki kod PHP 5.4 beri hangi cümledeki mevcut kısa dizi sözdizimi kullanılarak yazılır array()ile []. http://php.net/manual/en/language.types.array.php

Ofset dizinli ve ad dizinli dizilerde çalışır

$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);

Çıktı:

["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

Bunu uzun zaman önce biliyorum, ama bu benim için çalıştı.

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

2

Bu Php benim diziler kopyalamak yoludur:

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

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

Bu çıktılar:

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

2
Neden sadece söylemiyorsun $test2 = $test;? ArrayObjectBurada hangi problem çözülüyor?
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

Bulduğum en güvenli ve en ucuz yol:

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

Bunun da diziyi yeniden endeksleme avantajı vardır.

Bu, ilişkilendirilebilir dizi (karma) üzerinde beklendiği gibi çalışmaz, ancak önceki yanıtın çoğunda olmaz.


1

ArrayObject öğesinin bir kopyasını oluşturur

<?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);

?>

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


0

Bunu tanımlayın:

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

$ _ARRAY $ _ARRAY2 klasörüne kopyala:

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

0

Php dizisinde, bu dizinin kopyasını almak için bunları diğer değişkene atamanız yeterlidir. Ancak önce, dizi veya arrayObject veya stdObject olsun, türünden emin olmanız gerekir.

Basit php dizisi için:

$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);

Sadece bir çözüm daha göndermek için;)


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

Hem anahtar hem de değerleri korur. 'A' dizisi 'b' dizisinin tam bir kopyasıdır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.