क्या एक PHP सरणी की प्रतिलिपि दूसरे को बनाने के लिए एक फ़ंक्शन है?


529

क्या एक PHP सरणी की प्रतिलिपि दूसरे को बनाने के लिए एक फ़ंक्शन है?

मुझे PHP सरणियों को कॉपी करने की कोशिश में कुछ बार जलाया गया है। मैं किसी वस्तु के अंदर परिभाषित एक सरणी को उसके बाहर वैश्विक रूप से कॉपी करना चाहता हूं।


वास्तव में देर से, लेकिन मेरे पर्यावरण में मैंने यह परीक्षण किया (और यह काम किया): फ़ंक्शन अरोपी (सरणी $ a) {वापसी $ a; } $ a1 = array (); for ($ i = 0; $ i <3; $ i ++) {$ a1 ["key- $ i"] = "value # $ i"; } $ a1 ["की-सब-एरे"] = ऐरे (1, 2, 3, 4); $ a2 = $ a1; $ a3 = arrayCopy ($ a1); के लिए ($ i = 0; $ i <3; $ i ++) {if (! is_array ($ a2 ["की- $ i"])) {$ a2 ["key- $ i"] = "परिवर्तित मूल्य # $ मैं"; }} $ a2 ["की-सब-एरे"] = ऐरे ("बदले हुए उप-एरे 1", "बदले हुए उप-एरे 2"); var_dump ($ A1); var_dump ($ A2); var_dump ($ a3); चाल है, समारोह में एक संदर्भ के रूप में सरणी पारित करने के लिए नहीं ;-)
स्वेन

जवाबों:


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
आपने सवाल का जवाब नहीं दिया। आपने केवल समस्या बताई। जो, ओपी के लिए, सबसे अधिक संभावना है कि वह क्या देख रहा था। हालांकि, मेरे लिए (और अन्य लोगों के लिए भी), लगभग चार साल बाद इसी तरह की समस्या के साथ, मेरे पास अभी भी मूल सरणी को संशोधित किए बिना एक सरणी को क्लोन करने का एक अच्छा तरीका नहीं है (जिसमें आंतरिक संकेत भी शामिल हैं)। मुझे लगता है कि यह मेरे लिए अपना प्रश्न पूछने का समय है।
एंड्रयू लार्सन

28
@AndrewLarsson लेकिन PHP डिफ़ॉल्ट रूप से ऐसा करती है - यही इसका सार है। हालाँकि, संदर्भों का समाधान नहीं किया जाता है, इसलिए यदि आपको इसकी आवश्यकता है, तो आपको सरणी को फिर से बदलना होगा और एक नया निर्माण करना होगा - इसी तरह, यदि स्रोत सरणी में ऑब्जेक्ट हैं, और आप उन क्लोन को चाहते हैं, तो आपको मैन्युअल रूप से करना होगा। यह भी ध्यान रखें कि PHP में संदर्भ सी में संकेत के समान नहीं हैं । आपके मामले के बारे में कुछ भी जाने बिना, मैं सुझाव दे सकता हूं कि पहले मामले में संदर्भ की एक सरणी होना अजीब है, खासकर यदि आप इलाज करने का इरादा नहीं रखते हैं। उन्हें संदर्भ के रूप में? उपयोग का मामला क्या है?
ट्रॉयल्सनको

1
@troelskn मैंने अपनी समस्या के समाधान के साथ इस प्रश्न का उत्तर जोड़ा: stackoverflow.com/a/17729234/1134804
एंड्रयू लार्सन

3
लेकिन जब यह वांछित व्यवहार नहीं है तो क्या होगा? सवाल पूछता है कि कैसे एक गहरी प्रतिलिपि बनाने के लिए। यह स्पष्ट रूप से वांछित नहीं है। आपका जवाब के अलावा कोई बेहतर है: $copy = $original;। यदि सरणी तत्व संदर्भ हैं, तो यह काम नहीं करता है।
doug65536 2

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

यदि सरणी बहुत बड़ी है तो संदर्भ का उपयोग करना महत्वपूर्ण हो सकता है। मुझे यकीन नहीं है, लेकिन मुझे लगता है कि इसे कम मेमोरी खपत और बेहतर प्रदर्शन के लिए नेतृत्व करना चाहिए (स्मृति में पूरे सरणी की प्रतिलिपि बनाने की आवश्यकता नहीं है)।
रोब्स

11
@robsch - कार्यक्रम तर्क के स्तर पर, सरणी की प्रतिलिपि बनाई गई है। लेकिन स्मृति में, इसे तब तक कॉपी नहीं किया जाएगा जब तक कि इसे संशोधित न किया जाए - क्योंकि PHP सभी प्रकारों के लिए कॉपी-ऑन-राइट शब्दार्थ का उपयोग करता है। stackoverflow.com/questions/11074970/…
जेसिका नाइट

@CoreyKnight जानने के लिए अच्छा है। इसके लिए शुक्रिया।
रॉब्सच

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
ध्यान रखें कि यह एक विशेष मामला है। इसके अलावा, ध्यान दें कि यह केवल पहले स्तर के संदर्भों को क्लोन करेगा। यदि आपके पास एक गहरी सरणी है, तो आपको गहरे नोड्स क्लोन नहीं मिलेंगे, यदि वे संदर्भ हैं। आपके मामले में एक मुद्दा नहीं हो सकता है, लेकिन इसे ध्यान में रखें।
ट्रॉयल्सनको

4
@troelskn मैंने कुछ पुनरावृत्ति जोड़कर इसे ठीक किया। यह फ़ंक्शन अब मिश्रित प्रकारों सहित किसी भी प्रकार के सरणी पर काम करेगा। यह सरल सारणियों के लिए भी काम करता है, इसलिए यह अब स्थानीयकृत नहीं है। यह मूल रूप से एक सार्वभौमिक सरणी क्लोनिंग मशीन है। यदि आप गहरे हैं तो आपको अपनी वस्तुओं में __clone () फ़ंक्शन को परिभाषित करने की आवश्यकता होगी, लेकिन यह इस फ़ंक्शन के "दायरे" (खराब वाक्य के लिए खेद है) से परे है।
एंड्रयू लार्सन

2
मेरा दृढ़ता से मानना ​​है कि यह इस प्रश्न का वास्तविक उत्तर है, जिस तरह से मैंने वास्तव में गहरी एक सरणी को कॉपी करने के लिए देखा है जिसमें ऑब्जेक्ट शामिल हैं।
पैट्रिक

यह ऑब्जेक्ट गुण को पुनरावृत्त नहीं करता है जिसमें अन्य सरणियाँ और संदर्भित ऑब्जेक्ट हो सकते हैं।
ya.teck

6
यह प्रयोग __FUNCTION__शानदार है।
zessx

29

जब तुम करोगे

$array_x = $array_y;

PHP सरणी को कॉपी करता है, इसलिए मुझे यकीन नहीं है कि आपने कैसे जला दिया होगा। आपके मामले के लिए,

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

ठीक काम करना चाहिए।

जलने के क्रम में, मुझे लगता है कि आपको या तो संदर्भों का उपयोग करना होगा या सरणियों के अंदर वस्तुओं का क्लोन बनाना होगा।


12
इसके लिए +1: "या सरणियों के अंदर वस्तुओं की क्लोनिंग की उम्मीद करना"
मैल्सी

20

array_merge() एक ऐसा कार्य है जिसमें आप PHP में एक सरणी को दूसरे में कॉपी कर सकते हैं।


4
हां, लेकिन कुंजियों को संशोधित किया जाएगा, उद्धरण: संख्यात्मक कुंजियों के साथ इनपुट सरणी में मान परिणाम सरणी में शून्य से शुरू होने वाली वृद्धि की कुंजी के साथ बदल दिए जाएंगे।
ज़मनीट्स

चाबियाँ बनाए रखने के लिए @zamnuts $a_c = array_combine(array_keys($a), array_values($a)):।
CPHPython

18

सरल और गहरी प्रतिलिपि बनाता है सभी लिंक को तोड़ने

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

4
आम तौर पर यह ठीक काम करता है, हालांकि कुछ मामलों में यह अपवाद फेंक सकता है क्योंकि सभी चर क्रमबद्ध नहीं हैं (उदाहरण के लिए क्लोजर और डेटाबेस कनेक्शन)।
येटेक ya

एक और ध्यान देने वाली बात यह है कि यदि क्लास __wakeup मैजिक विधि को लागू करता है तो ऑब्जेक्ट रेफरेंस को रिस्टोर किया जा सकता है।
येट

धन्यवाद, अंत में कुछ ऐसा है जो वास्तव में काम करता है, न कि बहुत अधिक उत्थान वाले अन्य बोलचाल के उत्तर, वे निश्चित रूप से वस्तुओं की सरणी के साथ सौदा नहीं करते हैं जैसा कि प्रश्न में निर्दिष्ट है जहां सरणी में तत्वों की संख्या में परिवर्तन हो सकता है, लेकिन निश्चितता संदर्भों के संदर्भ में नहीं है वस्तुओं उनके अंदर
FentomX1

12

मुझे पसंद है array_replace(या array_replace_recursive)।

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

यह Object.assignजावास्क्रिप्ट से काम करता है ।

$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()क्लोन सरणियों का उपयोग करने के लिए काफी लोकप्रिय है ।
क्रिश्चियन

जेएस में हमारे पास कुंजी-मूल्य-जोड़े और ऐरे के लिए ऑब्जेक्ट है । PHP को इससे फर्क नहीं पड़ता है। गिने हुए अनुक्रमित के साथ PHP सरणियों के लिए, और यहां बताए गए अन्य सभी तरीके बहुत अच्छी तरह से काम करते हैं। लेकिन अगर आप कई की-वैल्यू-जोड़े को मर्ज करना चाहते हैं (जैसा कि जेएस-ऑब्जेक्ट्स के माध्यम से या स्प्रेड-सिंटैक्स के साथ भी संभव है ), अधिक उपयोगी हो सकता है। array_sliceObject.assignarray_replace
पुटजी सैन

@Christian ने सुझाव के लिए धन्यवाद दिया, array_values()जिसने मेरे उपयोग-मामले के लिए पूरी तरह से काम किया।
बिगसी

11

यदि आपके पास आपके सरणी में केवल मूल प्रकार हैं, तो आप ऐसा कर सकते हैं:

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

आपको मैन्युअल रूप से उन संदर्भों को अपडेट करने की आवश्यकता नहीं होगी जिन्हें
मैं जानता हूं कि यह सभी के लिए काम नहीं करेगा, लेकिन यह मेरे लिए काम करता है


4
+1 यह एक बहुत बुरी बात है, लेकिन तकनीकी रूप से सही और चतुर है। अगर मैंने इसे कोड में देखा तो मुझे हथेली का सामना करना पड़ेगा लेकिन मैं इसे पसंद नहीं कर सकता।
रिएक्टगुलर

4

चूंकि यह किसी भी उत्तर में शामिल नहीं था और अब PHP 5.3 में उपलब्ध है (माना जाता है कि मूल पोस्ट 5.2 का उपयोग कर रहा था)।

एक सरणी संरचना को बनाए रखने और इसके मूल्यों को बदलने के लिए मैं अपने उपयोग के मामले के आधार पर array_replaceया उपयोग करना पसंद array_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हल हो रही है?
नैट

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
foreach($a as $key => $val) $b[$key] = $val ;

कुंजी और मान दोनों को संरक्षित करता है। सरणी 'a' सरणी 'b' की एक सटीक प्रति है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.