Hi guys! I understand that my question kind lame but hope that there will be another answers, not just a "go-learn-php" Actually, I cant understand when we really need to clone an object For examle I saw such code in on of plugins: PHP: public function onMove(PlayerMoveEvent $event) { ... $to = clone $event->getFrom(); $event->setTo($to); } Do we really need here to use clone? Why? Another example: PHP: $item = Item::get(Item::ARROW, 0, 1); $this->inventory->addItem(clone $item); As I see, Item::get creates new object. So why do use clone here? Can you give me some hints please?
In PHP, objects are passed by reference (two variables point to the same memory address) by default so cloning is basically "copying" an object (two different copies of the variable are stored in memory) instead of passing it by reference. For example, PHP: $item = new Item(Item::CARROT, 0, 1);$item_ref = $item;$item_ref->setCount(20);echo $item->getCount(); Equals 20 -- whereas if you added the "clone" construct: PHP: $item = new Item(Item::CARROT, 0, 1);$item_ref = clone $item;$item_ref->setCount(20);echo $item->getCount(); It would equal 1. In the second example, the cloning does appear to be redundant as PocketMine already clones them when addItem() is called. Generally this shouldn't be too much of an issue other than the added overhead.
Usually, clone should only be used when the object is used as a struct. An object used as a struct when it is only used to pass multiple data. For example, an Item object passes multiple data: item ID, item damage, item count, extra item data. An object that is multiple-referenced and each instance has its unique meaning, such as a Player object, should not be cloned. Without cloning, you cannot naturally find two instances of Player object that are equal and represent the same thing.
So if I, for example want to store broken blocks list in onBlockBreak event handler after $b = $event->getBlock(); should I do $this->store[] = $b or $this->store[] = clone $b; ? And as I understood, while adding item (created by Item::get) to an inventory - cloning not needed, right? But why do we have such cloning in PocketMines's Player.php in checkNearEntities function ?
It is not advisable to store Block objects directly, because a Block object is actually a Position object (Block extends Position) too, which contains a strong reference to a Level object. Therefore, it is better to simply store an array of [$b->getId(), $b->getDamage()]. If you also want to store the position, make it save the level name instead of a reference to the level object so that PHP GC releases the memory for the level gracefully. (This is possibly a cause to many memory exhaustion issues) About checkNearEntities: it is not needed, but it is quite harmless to do it. After all, cloning an object, especially a small one like an Item object, is really a minor operation to the CPU.