Webstack
Bejelentkezés

Elfelejtetted a jelszavad?

Nem vagy még tag? Kattints ide és regisztrálj most!

Objektumok klónozása

PHP | tomizej  | 2013-02-23 08:00:00

Az objektumok referencia típusú változók. Programozásban ezen változók esetében két féle másolásról beszélhetünk: deep copy és shallow copy. Tükörfordításban alacsony, és mély másolás. Különbség a másolás módjában és a sebességben is van.

Objektumok sekély másolása (shallow copy)

A shallow copy esetében nem történik konkrét másolás, csak az objektum referenciája lesz megosztva, a változó csak a memória címet kapja meg. Máshogy megközelítve a dolgot, ha egy objektumot sekély másolással másolunk, a lemásolt objektum lényegében csak egy hivatkozás (referncia) lesz arra az objektumra, amiről másoltuk.

Az alábbi egyszerű példában tételezzük fel, hogy van egy sofőr osztályunk (Driver) és egy Autó osztályunk (Car). A sofőrnek van autója, az autónak pedig van üzemanyag tankja.

class Car {
    protected $type;
    public $fuel;
    public function __construct($type) {
        $this->type = $type;
    }
}

class Driver {
    public $name;
    public $car;
    public function __construct($name, Car $car) {
        $this->name = $name;
        $this->car = $car;
    }
    
    public function whoAmI() {
        echo "En vagyok $this->name. \n";
        echo "Az autómban {$this->car->fuel}liter üzemanyag van. \n";
    }
}

 

Létrehozunk egy sofőrt, beállítjuk az üzemanyag értékét (tankolunk). Majd lemásoljuk a sofőr objektumot. Az új soffőrt átnevezzük, az eredetivel pedig ismét tankolunk:

$zoli = new Driver('Zoli', new Car('Bmw'));
$zoli->car->fuel = 30;
$zoliMasolat =  $zoli;
$zoli->car->fuel = 90;
$zoliMasolat->name = 'Zoltán';
echo $zoli->whoAmI();
echo $zoliMasolat->whoAmI();

Ha a kódot lefuttatjuk, látjuk, hogy az eredeti objektumunk neve is megváltozózott, illetve másolatunk benzintankja is meggyarapodott.

 

Kimenet:

 

En vagyok Zoltán. Az autómban 90liter üzemanyag van.
En vagyok Zoltán. Az autómban 90liter üzemanyag van

Mivel a $zoliMasolat csak egy referencia, így ha valamely objektum állapota változik, akkor az összes példányra kihat.

A cél az lenne, hogy egy olyan másolatot készítsünk, ami külön áll az eredeti objektumtól, erre lesz jó a deep copy.

Objektumok mély másolása (deep copy)

A deep copy esetében konkrét másolás történik, új memóriaterület foglalás a háttérben. A „mély másolás" értelem szerűen lassabb. PHP-ben a clone kulcsszóval tudunk változót másolni. Az előző példánál maradva megpróbáljuk lemásolni az objektumot:

$zoli = new Driver('Zoli', new Car('Bmw'));
$zoli->car->fuel = 30;

$zoliMasolat = clone $zoli;

$zoli->name = 'Zoltán';
$zoli->car->fuel = 90;

echo $zoli->whoAmI();
echo $zoliMasolat->whoAmI();

Kimenet:

 

En vagyok Zoli. Az autómban 90liter üzemanyag van.
En vagyok Zoltán. Az autómban 90liter üzemanyag van

 

Az eredeti objektumunk neve nem változott, de nem teljesen értük el a célunk, mivel a másolat benzintankja ismét változott.

Fontos, hogy az objektumok klónozása során a becsomagolt osztályok csak sekély másolva lesznek!!! Ezt a problémát ki tudjuk küszöbölni a __clone() magic metódussal.

__clone()

A __clone() metódus akkor hívódik meg, ha egy objektumot klónozunk. A magic metódusokról bővebben a PHP Magic Metódusok, avagy különleges tagfüggvények cikksorozatunkban olvashatunk.

Ebben a metódusban gondoskodhatunk arról, hogy a becsomagolt objektumok is mély másolással (deep copy) legyenek másolva. A Driver osztályban implementáljuk a __clone() metódust:

class Driver {
//…
    public function __clone() {
       //Léterhozzuk az autó mély másolatát
        $this->car = clone $this->car;
    }
//…
}

Ha ismét megpróbáljuk másolni az objektumot (lefuttatjuk a deep copy –nál említett példakódot), megkapjuk a teljes másolatot.

 

Kimenet:

 

En vagyok Zoli. Az autómban 90liter üzemanyag van.
En vagyok Zoltán. Az autómban 30liter üzemanyag van.

 

Szerző: tomizej

címkék
Címkék: tutorial, php,

Hozzászólások

Hozzászóláshoz be kell jelentkezni!

Keress minket Facebookon
Ajánlások