PHP配列を別の配列にコピーする関数はありますか?


529

PHP配列を別の配列にコピーする関数はありますか?

PHPの配列をコピーしようとして何度か火傷しました。オブジェクトの内部で定義された配列をオブジェクトの外部のグローバルにコピーしたい。


本当に遅いですが、私の環境ではこれをテストしました(そしてそれはうまくいきました):function arrayCopy(array $ a){return $ a; } $ a1 = array(); for($ i = 0; $ i <3; $ i ++){$ a1 ["key- $ i"] = "value#$ 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"] = "変更された値#$私"; }} $ a2 ["key-sub-array"] = array( "changed sub-array 1"、 "changed sub-array 2"); var_dump($ a1); var_dump($ a2); var_dump($ a3); コツは、関数への参照として配列を渡さないことです;-)
Sven

回答:


926

PHPでは、配列はコピーによって割り当てられますが、オブジェクトは参照によって割り当てられます。この意味は:

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

収量:

array(0) {
}

一方:

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

収量:

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

ArrayObject配列のように機能するオブジェクトであるなどの複雑な機能に混乱する可能性があります。ただし、オブジェクトであるため、参照セマンティクスがあります。

編集:@AndrewLarssonは、以下のコメントでポイントを挙げています。PHPには、「参照」と呼ばれる特別な機能があります。これらは、C / C ++などの言語のポインターに多少似ていますが、まったく同じではありません。配列に参照が含まれている場合、配列自体はコピーによって渡されますが、参照は元のターゲットに解決されます。これはもちろん望ましい動作ですが、言及する価値があると思いました。


104
あなたは質問に答えませんでした。あなただけの問題を説明しました。これは、OPにとって、彼が探していたものと思われます。ただし、私(および他の人も)は、ほぼ4年後に同様の問題を抱えてここに来ましたが、元の配列(内部ポインターも含む)を変更せずに配列を複製する方法はまだありません。自分の質問をする時がきたと思います。
Andrew Larsson 2013

28
@AndrewLarssonしかし、PHPはデフォルトでそれを行います-それがその要点です。ただし、参照は解決されないため、必要な場合は、配列を再帰的に走査して新しい配列を作成する必要があります。同様に、ソース配列にオブジェクトが含まれていて、それらを複製する場合は、手動で行う必要があります。PHPでの参照はCでのポインターと同じではないことにも注意してください。特に処理するつもりがない場合は、最初のケースで参照の配列があるのはおかしいかもしれません。参照としてそれら?ユースケースは何ですか?
troelskn 2013

1
@troelskn私は私の問題の解決策とともにこの質問への回答を追加しました:stackoverflow.com/a/17729234/1134804
Andrew Larsson

3
しかし、それが望ましい動作ではない場合はどうでしょうか?質問は、深いコピーを作成する方法を尋ねます。それは明らかに望ましくありません。あなたの答えは次のとおり$copy = $original;です。配列要素が参照の場合は機能しません。
doug65536 2013

8
いつものphpように、このソリューションは常に機能するとは限らないため、予想される結果最も少なくなります。 印刷中に印刷します。どうやらいくつかの配列は参照によってコピーされます。$a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];array0$a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];array1
Tino

186

PHPはデフォルトで配列をコピーします。PHPでの参照は明示的である必要があります。

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

配列が巨大な場合、参照を使用することが重要になる場合があります。確かではありませんが、メモリの消費量が少なくなり、パフォーマンスが向上するはずです(配列全体をメモリにコピーする必要はありません)。
robsch 2016年

11
@robsch-プログラムロジックのレベルで、配列がコピーされます。しかし、メモリ内では、変更されるまで実際にはコピーされません-PHPはすべてのタイプにコピーオンライトセマンティクスを使用するためです。stackoverflow.com/questions/11074970/…–
ジェシカナイト

@CoreyKnight知っておきます。これありがとう。
robsch 2017

4
これはネストされた配列には当てはまらないことに注意してください。これらは参照であるため、混乱を
招きます

45

オブジェクトを含む配列がある場合、その内部ポインターに触れずにその配列のコピーを作成する必要があり、すべてのオブジェクトを複製する必要があります(コピーに変更を加えるときに元のオブジェクトを変更しないようにするため)配列)、これを使用します。

配列の内部ポインターに触れないための秘訣は、元の配列(またはその参照)ではなく、配列のコピーで作業していることを確認することです。そのため、関数パラメーターを使用すると、作業が完了します(したがって、これは配列を取る関数です)。

プロパティも複製したい場合は、オブジェクトに__clone()を実装する必要があることに注意してください。

この関数は、任意のタイプの配列(混合タイプを含む)で機能します。

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

1
これは少し特殊なケースであることを覚えておいてください。また、これは最初のレベルの参照のみを複製することに注意してください。深い配列がある場合、それらが参照である場合、より深いノードは複製されません。あなたのケースでは問題ではないかもしれませんが、それを覚えておいてください。
troelskn 2013

4
@troelskn再帰を追加して修正しました。この関数は、混合型を含むすべての型の配列で機能します。また、単純な配列でも同様に機能するため、ローカライズされていません。基本的には、ユニバーサルアレイクローンマシンです。オブジェクト内で__clone()関数が深い場合は、それを定義する必要がありますが、それはこの関数の「スコープ」を超えています(駄洒落のため申し訳ありません)。
Andrew Larsson 2013

2
これがこの質問に対する実際の答えであると強く信じています。オブジェクトを含む配列を実際にディープコピーするために見た唯一の方法です。
Patrick

他の配列や参照オブジェクトを持つ可能性のあるオブジェクトプロパティを反復しません。
ya.teck 2017年

6
この使用__FUNCTION__は素晴らしいです。
zessx 2017年

29

あなたがするとき

$array_x = $array_y;

PHPは配列をコピーするので、どのように焼かれたかはわかりません。あなたの場合、

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

正常に動作するはずです。

書き込みを行うには、参照を使用しているか、配列内のオブジェクトが複製されることを期待している必要があると思います。


12
このための+1:「または配列内のオブジェクトがクローン化されることを期待しています」
Melsi


18

シンプルでディープコピーがすべてのリンクを壊します

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

4
一般的には問題なく動作しますが、すべての変数がシリアライズ可能であるとは限らないため(たとえば、クロージャーやデータベース接続など)、例外がスローされる場合があります。
ya.teck 2017年

注意すべきもう1つの点は、クラスが__wakeupマジックメソッドを実装している場合、オブジェクト参照を復元できることです。
ya.teck 2017年

おかげで、最終的には実際に機能するものであり、多数の賛成票を持つ他のbollockの回答ではありません。問題となっているように、配列内の要素の数が変わる可能性のあるオブジェクトの配列は処理されませんでしたが、それらの内部のオブジェクト
FentomX1

12

私はarray_replace(またはarray_replace_recursive)が好きです。

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

Object.assignJavaScriptのように動作します。

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

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

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

結果になります

// 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
何についてarray_slice($arr, 0)か、キーを気にしない場合は、array_values($arr)?配列で検索するよりも高速かもしれません。また、JavaScriptでは、Array.slice()配列の複製に使用するのが一般的です。
クリスチャン

JSには、キーと値のペアと配列のオブジェクトがあります。PHPではこの違いはありません。番号付けされたインデックスを持つPHP配列の場合、およびここで説明されている他のすべてのメソッドは非常にうまく機能します。ただし、複数のキーと値のペアをマージしたい場合(JS-Objects via またはspread-syntaxでも可能です)、より便利な場合があります。array_sliceObject.assignarray_replace
Putzi San 2018

@Christian array_values()は、私のユースケースに完全に機能する提案をありがとうございました。
-bigsee

11

配列に基本型のみがある場合、これを行うことができます:

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

手動で参照を更新する必要はありません
私はそれがすべての人に役立つわけではないことを知っていますが、それは私にとってはうまくいきました


4
+1これは行うのが本当に悪いことですが、技術的には正しく賢いです。コードでこれを見たとしたら、私は手のひらに直面するでしょうが、それは好きではありません。
Reactgular 2016

4

これはどの回答にも含まれていなかったため、PHP 5.3で使用できるようになりました(元の投稿が5.2を使用していたと想定)。

配列構造を維持し、その値を変更するために、私は使用することを好むarray_replacearray_replace_recursive、使用例に依存します。

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

以下は、インデックス化された順序を維持でき、参照を削除できることを使用array_replaceしてarray_replace_recursive説明する例です。

http://ideone.com/SzlBUZ

以下のコードを置き換えPHP 5.4以降で利用可能短い配列構文を使用して書かれているarray()[]http://php.net/manual/en/language.types.array.php

オフセットインデックス付き配列と名前付きインデックス配列のどちらでも機能します

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

出力:

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

私はずっと前にこれを知っていますが、これは私にとってはうまくいきました。

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

2

これは私がPhpで配列をコピーしている方法です:

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

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

これは出力します:

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

2
なぜ言ってみません$test2 = $test;か?ArrayObjectここでどのような問題を解決していますか?
2015

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

私が見つけた最も安全で最も安い方法は:

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

これには、配列のインデックスを再作成する利点もあります。

これは連想配列(ハッシュ)では期待どおりに機能しませんが、以前のほとんどの回答では機能しません。


1

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

?>

https://www.php.net/manual/en/arrayobject.getarraycopy.phpから



0

PHP配列では、それらを他の変数に割り当てて、その配列のコピーを取得する必要があります。しかし、最初に、それが配列であるか、arrayObjectであるか、stdObjectであるかにかかわらず、そのタイプを確認する必要があります。

単純なphp配列の場合:

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

$b = $a;

var_dump($b);

output:

array:1 [
  "data" => 10
]


0

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

もう1つのソリューションを投稿するだけです;)


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

キーと値の両方を保持します。配列 'a'は配列 'b'の正確なコピーです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.