मैं PHP में किसी ऑब्जेक्ट की प्रतिलिपि कैसे बनाऊं?


168

ऐसा प्रतीत होता है कि PHP में वस्तुओं को संदर्भ द्वारा पारित किया जाता है। यहां तक ​​कि असाइनमेंट ऑपरेटर्स ऑब्जेक्ट की कॉपी बनाते हुए दिखाई नहीं देते हैं।

यहाँ एक सरल, आकस्मिक प्रमाण दिया गया है:

<?php

class A {
    public $b;
}


function set_b($obj) { $obj->b = "after"; }

$a = new A();
$a->b = "before";
$c = $a; //i would especially expect this to create a copy.

set_b($a);

print $a->b; //i would expect this to show 'before'
print $c->b; //i would ESPECIALLY expect this to show 'before'

?>

दोनों प्रिंट मामलों में मुझे 'के बाद' मिल रहा है

इसलिए, मैं संदर्भ से नहीं, $ a से set_b () को कैसे पास करूं ?


2
बहुत कम मामले हैं, जहां आप वास्तव में इस व्यवहार को चाहते हैं। इसलिए यदि आप अक्सर इसका उपयोग करते हुए अपना स्वयं का पता लगाते हैं, तो शायद आपके कोड लिखने के तरीके के साथ कुछ और मौलिक गलत है?
troelskn

1
नहीं, अभी तक इसका इस्तेमाल करने की जरूरत नहीं है।
निक स्टिनमेट्स

(object) ((array) $objectA)आप बेहतर प्रदर्शन के साथ एक ही वांछित परिणाम प्राप्त कर सकते हैं clone $objectAया फिर उपयोग कर सकते हैं new stdClass
बिन्नामिन

जवाबों:


284

PHP में 5+ ऑब्जेक्ट्स संदर्भ द्वारा पारित किए जाते हैं। PHP 4 में वे मूल्य द्वारा पारित किए जाते हैं (इसीलिए इसके संदर्भ में रनटाइम पास था, जो कि पदावनत हो गया)।

आप PHP5 में ऑब्जेक्ट को कॉपी करने के लिए 'क्लोन' ऑपरेटर का उपयोग कर सकते हैं:

$objectB = clone $objectA;

इसके अलावा, यह सिर्फ वस्तुओं है कि संदर्भ से पारित कर रहे हैं, नहीं सब कुछ के रूप में आप अपने सवाल में कहा है ...


बस जो इसे पढ़ रहा है, उसे जोड़ना चाहते हैं, कि क्लोनिंग मूल वस्तु का संदर्भ रखेगा। क्लोन किए गए ऑब्जेक्ट का उपयोग करके MySQL के प्रश्नों को चलाने से अप्रत्याशित परिणाम हो सकते हैं, क्योंकि निष्पादन रैखिक फैशन में नहीं हो सकता है।
Ælex

20
एक आम ग़लतफ़हमी को ठीक करने के लिए (मुझे लगता है कि PHP डॉक्स भी गलत हो जाते हैं!) PHP 5 की वस्तुओं को "संदर्भ द्वारा पारित नहीं किया जाता है"। जावा में, उनके पास एक अतिरिक्त स्तर का अप्रत्यक्ष है - चर एक "ऑब्जेक्ट पॉइंटर" को इंगित करता है, और एक ऑब्जेक्ट को इंगित करता है। इस प्रकार दो चर समान मान के संदर्भ के बिना एक ही वस्तु को इंगित कर सकते हैं । इसे इस उदाहरण से देखा जा सकता है: $a = new stdClass; $b =& $a; $a = 42; var_export($b);यहां चर का$b संदर्भ दिया गया है $a ; यदि आप =&एक सामान्य से बदलते हैं =, तो यह एक संदर्भ नहीं है, और अभी भी मूल वस्तु की ओर इशारा करता है।
IMSoP

संदर्भ द्वारा रनटाइम पास एक बुरा विचार है, क्योंकि यह फ़ंक्शन के प्रभाव को विनिर्देश के बजाय फ़ंक्शन के कार्यान्वयन पर निर्भर करता है। यह कुछ भी नहीं करने के लिए डिफ़ॉल्ट रूप से पास होने के साथ कुछ नहीं मिला है।
ओसवाल्ड

1
@ क्या आप अपनी टिप्पणी पर विस्तार से बता सकते हैं? (या तो यहां या कहीं और।) आपकी बात थोड़ा अस्पष्ट आईएमओ से निकलती है।
क्रिस मिडलटन

@ChrisMiddleton C या C ++ की शर्तों के बारे में सोचें: यदि आपने किसी ऑब्जेक्ट का संदर्भ दिया है जो free'd, दायरे से बाहर या जारी किया गया है, तो आपका क्लोन किया हुआ संदर्भ अमान्य है। इस प्रकार आपको मूल वस्तु के साथ जो हुआ है, उसके आधार पर आपको अपरिभाषित व्यवहार मिल सकता है , जिसके लिए आप क्लोनिंग के माध्यम से एक संदर्भ रखते हैं।
Ælex

103

उत्तर आमतौर पर जावा पुस्तकों में पाए जाते हैं।

  1. क्लोनिंग: यदि आप क्लोन विधि को ओवरराइड नहीं करते हैं, तो डिफ़ॉल्ट व्यवहार उथली प्रति है। यदि आपकी वस्तुओं में केवल आदिम सदस्य चर हैं, तो यह पूरी तरह से ठीक है। लेकिन सदस्य चर के रूप में एक अन्य वस्तु के साथ एक टाइपलेस भाषा में, यह एक सिरदर्द है।

  2. क्रमबद्धता / अक्रमांकन

$new_object = unserialize(serialize($your_object))

यह ऑब्जेक्ट की जटिलता के आधार पर भारी लागत के साथ गहरी प्रतिलिपि प्राप्त करता है।


4
पीएचपी में डीईईपी कॉपी करने के लिए +1 शानदार, बढ़िया, बढ़िया तरीका, बहुत आसान भी। इसके बजाय मैं आपको PHP क्लोन कीवर्ड द्वारा प्रस्तुत मानक उथले प्रति के बारे में कुछ पूछना चाहता हूं, आपने कहा कि केवल आदिम सदस्य चर की प्रतिलिपि बनाई जाती है: क्या PHP सरणियों / तारों को आदिम सदस्य चर माना जाता है, इसलिए वे नकल करते हैं, क्या मैं सही हूं?
मार्को डेमायो

3
किसी को भी इसे लेने के लिए: एक "उथली" प्रति ( खेलने में $a = clone $bकोई जादू के __clone()तरीकों के साथ ) $b, शब्द में वस्तु के प्रत्येक गुण को देखने के बराबर है , और उसी वर्ग के नए सदस्य को उसी संपत्ति में असाइन करना, का उपयोग करके =। वे गुण जो ऑब्जेक्ट नहीं हैं clone, d नहीं मिलेंगे और न ही ऑब्जेक्ट किसी सरणी के अंदर; वही संदर्भ के लिए बाध्य चर के लिए जाता है; बाकी सब कुछ सिर्फ एक मूल्य है, और किसी भी असाइनमेंट की तरह ही कॉपी किया जाता है।
IMSoP

3
उत्तम! json_decode (json_encode ($ obj)); निजी / संरक्षित संपत्तियों और किसी भी विधि का क्लोन न करें ...
अनजाना

बहुत बढ़िया! मैं आखिरकार PhpStorm की त्रुटि से मुक्त हो गया; Call to method __clone from invalid context:)
संख्या

मित्र को ऐसा करते समय PHP पार्स त्रुटि हो रही है: $new_date = (clone $date_start)->subDays(1);यह के साथ विफल रहता है (), अगर मैं उन्हें हटा देता हूं तो मुझे एक अलग त्रुटि मिलती है। बात यह है, हम ठीक उसी php का उपयोग करते हैं 7.2.3 और मेरा काम ठीक है। कोई विचार? हर जगह खोजा गया ..
भावुकता

21

पिछली टिप्पणी के अनुसार, यदि आपके पास सदस्य चर के रूप में एक और वस्तु है, तो निम्न कार्य करें:

class MyClass {
  private $someObject;

  public function __construct() {
    $this->someObject = new SomeClass();
  }

  public function __clone() {
    $this->someObject = clone $this->someObject;
  }

}

अब आप क्लोनिंग कर सकते हैं:

$bar = new MyClass();
$foo = clone $bar;


4

बस स्पष्ट करने के लिए PHP लिखने पर कॉपी का उपयोग करता है, इसलिए मूल रूप से सब कुछ एक संदर्भ है जब तक आप इसे संशोधित नहीं करते हैं, लेकिन ऑब्जेक्ट के लिए आपको क्लोन और __clone () जादू पद्धति का उपयोग करने की आवश्यकता होती है जैसे स्वीकृत उत्तर में।


1

यह कोड क्लोन तरीकों की मदद करता है

class Foo{

    private $run=10;
    public $foo=array(2,array(2,8));
    public function hoo(){return 5;}


    public function __clone(){

        $this->boo=function(){$this->hoo();};

    }
}
$obj=new Foo;

$news=  clone $obj;
var_dump($news->hoo());

यह कोड थोड़ा बेकार है, यह काम करेगा भले ही आप __clone पद्धति को हटा दें :)
amik

1

मैं कुछ परीक्षण कर रहा था और यह मिला:

class A {
  public $property;
}

function set_property($obj) {
  $obj->property = "after";
  var_dump($obj);
}

$a = new A();
$a->property = "before";

// Creates a new Object from $a. Like "new A();"
$b = new $a;
// Makes a Copy of var $a, not referenced.
$c = clone $a;

set_property($a);
// object(A)#1 (1) { ["property"]=> string(5) "after" }

var_dump($a); // Because function set_property get by reference
// object(A)#1 (1) { ["property"]=> string(5) "after" }
var_dump($b);
// object(A)#2 (1) { ["property"]=> NULL }
var_dump($c);
// object(A)#3 (1) { ["property"]=> string(6) "before" }

// Now creates a new obj A and passes to the function by clone (will copied)
$d = new A();
$d->property = "before";

set_property(clone $d); // A new variable was created from $d, and not made a reference
// object(A)#5 (1) { ["property"]=> string(5) "after" }

var_dump($d);
// object(A)#4 (1) { ["property"]=> string(6) "before" }

?>

1

इस उदाहरण में हम iPhone क्लास बनाएंगे और क्लोनिंग से इसकी सटीक कॉपी बनाएंगे

class iPhone {

public $name;
public $email;

    public function __construct($n, $e) {

       $this->name = $n;
       $this->email = $e;

    }
}


$main = new iPhone('Dark', 'm@m.com');
$copy = clone $main;


// if you want to print both objects, just write this    

echo "<pre>"; print_r($main);  echo "</pre>";
echo "<pre>"; print_r($copy);  echo "</pre>";

-1

यदि आप किसी भिन्न उदाहरण में किसी ऑब्जेक्ट के गुणों को पूरी तरह से कॉपी करना चाहते हैं, तो आप इस तकनीक का उपयोग करना चाहते हैं:

इसे JSON पर सीरियल करें और फिर ऑब्जेक्ट पर वापस डी-सीरियल करें।


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