PHP 배열을 다른 배열로 복사하는 기능이 있습니까?


529

PHP 배열을 다른 배열로 복사하는 기능이 있습니까?

PHP 배열을 복사하려고 여러 번 화상을 입었습니다. 객체 내부에 정의 된 배열을 외부의 전역으로 복사하려고합니다.


정말 늦었지만 내 환경에서 이것을 테스트하고 작동했습니다. function arrayCopy (array $ a) {return $ a; } $ a1 = 배열 ​​(); for ($ i = 0; $ i <3; $ i ++) {$ a1 [ "key- $ i"] = "값 # $ i"; } $ a1 [ "key-sub-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 ( "변경된 하위 배열 1", "변경된 하위 배열 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에는 "references"라는 특별한 기능이 있습니다. 그것들은 C / C ++와 같은 언어의 포인터와 다소 유사하지만 동일하지는 않습니다. 배열에 참조가 포함되어 있으면 배열 자체가 사본으로 전달되는 동안 참조는 여전히 원래 대상으로 해석됩니다. 물론 그것은 일반적으로 원하는 행동이지만 언급 할 가치가 있다고 생각했습니다.


104
당신은 질문에 대답하지 않았습니다. 문제에 대해서만 설명했습니다. OP의 경우 가장 가능성이 높은 것은 무엇입니까? 그러나 거의 4 년 후 비슷한 문제로 여기에 오는 나 (그리고 다른 사람들도)에도 원래 배열 (내부 포인터도 포함)을 수정하지 않고 배열을 복제하는 좋은 방법이 없습니다. 나는 내 자신의 질문을 할 때가되었다고 생각한다.
Andrew Larsson

28
@AndrewLarsson 그러나 PHP는 기본적으로 그렇게합니다. 참조는 해결되지 않으므로 필요한 경우 배열을 재귀 적으로 탐색하고 새 배열을 작성해야합니다. 마찬가지로 소스 배열에 오브젝트가 포함되어 있고이를 복제하려는 경우 수동으로 수행해야합니다. PHP의 참조는 C의 포인터와 동일 하지 않다는 것을 명심하십시오 . 귀하의 사례에 대해 전혀 모르는 경우, 특히 치료하려는 의도가없는 경우 첫 번째 사례에 일련의 참조가있는 것이 이상하다고 제안 할 수 있습니다 그것들을 참조로? 사용 사례는 무엇입니까?
troelskn

1
@troelskn 내 문제에 대한 해결책 으로이 질문에 대한 답변을 추가했습니다. stackoverflow.com/a/17729234/1134804
Andrew Larsson

3
그러나 바람직한 행동이 아닌 경우는 어떻습니까? 질문은 카피 를 만드는 방법을 묻습니다 . 분명히 바람직하지 않습니다. 귀하의 답변은 $copy = $original;. 배열 요소가 참조 인 경우 작동하지 않습니다.
doug65536

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. 분명히 일부 배열은 참조로 복사됩니다.
티노

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

11
@robsch-프로그램 논리 수준에서 배열이 복사됩니다. 그러나 메모리에서는 수정 될 때까지 실제로 복사되지 않습니다. PHP는 모든 유형에 대해 기록 중 복사 의미를 사용하기 때문입니다. stackoverflow.com/questions/11074970/…
제시카 기사

@CoreyKnight 알아두면 좋습니다. 감사합니다.
robsch

4
이것은 중첩 배열에 대해서는 사실이 아니며, 참조이며 따라서 엉망으로 끝납니다
MightyPork

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

4
@troelskn 나는 재귀를 추가하여 그것을 고쳤다. 이 함수는 이제 혼합 유형을 포함한 모든 유형의 배열에서 작동합니다. 또한 간단한 배열에서도 잘 작동하므로 더 이상 지역화되지 않습니다. 기본적으로 범용 배열 복제기입니다. 객체가 깊다면 __clone () 함수를 정의해야하지만,이 함수의 "범위"를 넘어선 것입니다.
앤드류 라르손

2
나는 이것이 이것이이 질문에 대한 실제 답이라고 믿습니다. 실제로 객체를 포함하는 배열을 딥 카피하는 유일한 방법입니다.
Patrick

다른 배열과 참조 된 객체가있을 수있는 객체 속성을 반복하지 않습니다.
ya.teck

6
이 사용 __FUNCTION__은 훌륭합니다.
zessx

29

당신이 할 때

$array_x = $array_y;

PHP는 배열을 복사하므로 어떻게 구울 수 있었는지 잘 모르겠습니다. 귀하의 경우

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

잘 작동합니다.

화상을 입기 위해서는 참조를 사용하거나 어레이 내부의 객체가 복제 될 것으로 예상했을 것입니다.


12
+1 : "또는 배열 내부의 객체가 복제 될 것으로 예상"
Melsi


18

간단하고 깊은 링크로 모든 링크를 끊습니다.

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

4
일반적으로 잘 작동하지만 경우에 따라 모든 변수를 직렬화 할 수있는 것은 아니므로 (예 : 클로저 및 데이터베이스 연결) 예외가 발생할 수 있습니다.
ya.teck

클래스가 __wakeup magic 메소드를 구현하면 객체 참조를 복원 할 수 있습니다.
ya.teck

감사합니다. 마지막으로 작동하는 많은 볼록 답변이 아닌 실제로 작동하는 무언가는 배열의 요소 수가 변경 될 수있는 질문에 지정된대로 객체 배열을 처리하지 않았지만 분명히 내부 개체
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)? 배열에서 검색하는 것보다 빠를 것이라고 생각합니다. 또한 자바 스크립트에서는 Array.slice()배열을 복제 하는 데 널리 사용 됩니다.
Christian

JS에는 키-값 쌍 및 Array에 대한 Object 가 있습니다 . PHP는 이러한 차이를 만들지 않습니다. 번호가 매겨진 인덱스가있는 PHP 배열 및 여기에 언급 된 다른 모든 방법은 매우 효과적입니다. 당신은 (그것을 통해 JS-객체로도 가능으로 여러 키 - 값 쌍을 병합 싶은 경우 또는 확산 구문 ), 더 유용 할 수 있습니다. array_sliceObject.assignarray_replace
Putzi San

@Christian array_values()은 내 유스 케이스에 완벽하게 작동 하는 제안에 감사드립니다 .
bigsee

11

배열에 기본 유형 만있는 경우 다음을 수행 할 수 있습니다.

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

참조를 수동으로 업데이트 할 필요
는 없지만 모든 사람에게 적용되지는 않지만 알고 있습니다.


4
+1 이것은 정말 나쁜 일이지만 기술적으로 정확하고 영리합니다. 코드에서 이것을 보았을 때 손바닥에 직면 할 수는 있지만 도울 수는 없지만 좋아합니다.
Reactgular

4

이 답변에 대해서는 다루지 않았으므로 이제 PHP 5.3에서 사용할 수 있습니다 (원래 게시물이 5.2를 사용한다고 가정).

배열 구조를 유지하고 그 값을 변경하기 위해 사용 array_replace하거나 array_replace_recursive사용 사례에 따라 선호합니다 .

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

여기서 사용하는 예이다 array_replacearray_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해결되고 있습니까?
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

내가 찾은 가장 안전하고 저렴한 방법은 다음과 같습니다.

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

이것을 정의하십시오 :

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

$ _ARRAY를 $ _ARRAY2에 복사하십시오.

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

0

PHP 배열에서는 해당 변수를 다른 변수에 할당하면 해당 배열의 복사본을 얻을 수 있습니다. 그러나 먼저 배열인지 arrayObject인지 stdObject인지 유형을 확인해야합니다.

간단한 PHP 배열의 경우 :

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

하나 이상의 솔루션을 게시하십시오.)


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

키와 값을 모두 유지합니다. 배열 'a'는 배열 'b'의 정확한 사본입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.