Op het moment ben ik bezig met het clonen van een lijst. Ik heb een class ArrayList, welke kwa werking veel op die van .NET framework lijkt. Voor het voorbeeld heb ik heb even in het klein nagemaakt, maar de onderliggende werking is nog hetzelfde.
Als test object heb ik de volgende class even gemaakt:
Voordat ik naar het clonen van de ArrayList ga zal ik eerst even de stappen aangeven welke ik al heb getest om te laten zien dat opzichzelf alles wel werkt.
Ik verwacht twee lines met Fiets en Trein, deze waardes worden gevolgd door een unieke code die de instantie vertegenwoordig.
In het midden zit het verschil, dus dit werkt.
Volgende stap een lege ArrayList clonen en één object er in plaatsen.
Verwacht, twee unieke codes, en dat krijg ik ook. Wanneer ik print_r uitvoer op de lijsten dan zie ik dat lijst 1 leeg is en lijst 2 heeft één object met als naam 'Trein'. Gevulde lijsten clonen en daarbij aan toevoegen zorgt er ook voor dat de ik verschillende lijsten zie.
Maar nu doe ik het volgende:
Ik verwacht dat het object in de gekloonde lijst van naam veranderd. Maar om één of andere reden wijzigd hij de naam van het object in $list3 ook. Als ik nu de volgende code uitvoer:
Zie ik ook dat de hashcodes van de objecten precies hetzelfde zijn. Als ik de ArrayList clone dan gaat hij daadwerkelijk naar Object::__clone, want als ik hier een 'throw new Exception' in gooi dan gaat hij keihard op zijn bek.
Wat doe ik verkeerd?
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| class ArrayList { protected $_InnerList = array(); public function Add($object) { $this->_InnerList[] = $object; } public function Item($index) { return $this->_InnerList[$index]; } public function __clone() { $outputList = new ArrayList(); foreach($this->_InnerList as $item) $outputList->Add(clone $item); return $outputList; } } |
Als test object heb ik de volgende class even gemaakt:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| class Object { public $Name; public function __construct($name) { $this->Name = $name; } public function __clone() { return new Object($this->Name); } } |
Voordat ik naar het clonen van de ArrayList ga zal ik eerst even de stappen aangeven welke ik al heb getest om te laten zien dat opzichzelf alles wel werkt.
PHP:
1
2
3
4
5
6
| $obj1 = new Object("Fiets"); $obj2 = clone $obj1; $obj2->Name = "Trein"; printf('%s - %s' . PHP_EOL, str_pad($obj1->Name, 10), spl_object_hash($obj1)); printf('%s - %s' . PHP_EOL, str_pad($obj2->Name, 10), spl_object_hash($obj2)); |
Ik verwacht twee lines met Fiets en Trein, deze waardes worden gevolgd door een unieke code die de instantie vertegenwoordig.
code:
1
2
| Fiets - 000000006672dbdb0000000036b51097 Trein - 000000006672dbd80000000036b51097 |
In het midden zit het verschil, dus dit werkt.
Volgende stap een lege ArrayList clonen en één object er in plaatsen.
PHP:
1
2
3
4
5
6
| $list1 = new ArrayList(); $list2 = clone $list1; $list2->Add(new Object('Trein')); echo "List: " . spl_object_hash($list1) . PHP_EOL; echo "List: " . spl_object_hash($list2) . PHP_EOL; |
Verwacht, twee unieke codes, en dat krijg ik ook. Wanneer ik print_r uitvoer op de lijsten dan zie ik dat lijst 1 leeg is en lijst 2 heeft één object met als naam 'Trein'. Gevulde lijsten clonen en daarbij aan toevoegen zorgt er ook voor dat de ik verschillende lijsten zie.
Maar nu doe ik het volgende:
PHP:
1
2
3
4
5
| $list3 = new ArrayList(); $list3->Add(new Object("Fiets")); $cloneList = clone $list3; $cloneList->Item(0)->Name = 'Trein'; |
Ik verwacht dat het object in de gekloonde lijst van naam veranderd. Maar om één of andere reden wijzigd hij de naam van het object in $list3 ook. Als ik nu de volgende code uitvoer:
PHP:
1
2
| printf('%s - %s' . PHP_EOL, str_pad($list3->Item(0)->Name, 10), spl_object_hash($list3->Item(0))); printf('%s - %s' . PHP_EOL, str_pad($cloneList->Item(0)->Name, 10), spl_object_hash($cloneList->Item(0))); |
Zie ik ook dat de hashcodes van de objecten precies hetzelfde zijn. Als ik de ArrayList clone dan gaat hij daadwerkelijk naar Object::__clone, want als ik hier een 'throw new Exception' in gooi dan gaat hij keihard op zijn bek.
Wat doe ik verkeerd?