diff --git a/src/PriorityQueue.php b/src/PriorityQueue.php index 6f063419b..3a40e3634 100644 --- a/src/PriorityQueue.php +++ b/src/PriorityQueue.php @@ -31,11 +31,11 @@ * Re-usable, serializable priority queue implementation * * SplPriorityQueue acts as a heap; on iteration, each item is removed from the - * queue. If you wish to re-use such a queue, you need to clone it first. This + * queue. If you wish to re-use such a queue, you need to clone it first. This * makes for some interesting issues if you wish to delete items from the queue, * or, as already stated, iterate over it multiple times. * - * This class aggregates items for the queue itself, but also composes an + * This class aggregates items for the queue itself, but also composes an * "inner" iterator in the form of an SplPriorityQueue object for performing * the actual iteration. * @@ -73,9 +73,9 @@ class PriorityQueue implements Countable, IteratorAggregate, Serializable * Insert an item into the queue * * Priority defaults to 1 (low priority) if none provided. - * - * @param mixed $data - * @param int $priority + * + * @param mixed $data + * @param int $priority * @return PriorityQueue */ public function insert($data, $priority = 1) @@ -95,11 +95,11 @@ public function insert($data, $priority = 1) * This is different than {@link extract()}; its purpose is to dequeue an * item. * - * This operation is potentially expensive, as it requires + * This operation is potentially expensive, as it requires * re-initialization and re-population of the inner queue. - * + * * Note: this removes the first item matching the provided item found. If - * the same item has been added multiple times, it will not remove other + * the same item has been added multiple times, it will not remove other * instances. * * @param mixed $datum @@ -128,7 +128,7 @@ public function remove($datum) /** * Is the queue empty? - * + * * @return bool */ public function isEmpty() @@ -138,7 +138,7 @@ public function isEmpty() /** * How many items are in the queue? - * + * * @return int */ public function count() @@ -148,7 +148,7 @@ public function count() /** * Peek at the top node in the queue, based on priority. - * + * * @return mixed */ public function top() @@ -157,8 +157,8 @@ public function top() } /** - * Extract a node from the inner queue and sift up - * + * Extract a node from the inner queue and sift up + * * @return mixed */ public function extract() @@ -171,11 +171,11 @@ public function extract() * * SplPriorityQueue acts as a heap, which typically implies that as items * are iterated, they are also removed. This does not work for situations - * where the queue may be iterated multiple times. As such, this class - * aggregates the values, and also injects an SplPriorityQueue. This method - * retrieves the inner queue object, and clones it for purposes of + * where the queue may be iterated multiple times. As such, this class + * aggregates the values, and also injects an SplPriorityQueue. This method + * retrieves the inner queue object, and clones it for purposes of * iteration. - * + * * @return SplPriorityQueue */ public function getIterator() @@ -186,7 +186,7 @@ public function getIterator() /** * Serialize the data structure - * + * * @return string */ public function serialize() @@ -198,8 +198,8 @@ public function serialize() * Unserialize a string into a PriorityQueue object * * Serialization format is compatible with {@link Zend\Stdlib\SplPriorityQueue} - * - * @param string $data + * + * @param string $data * @return void */ public function unserialize($data) @@ -215,8 +215,8 @@ public function unserialize($data) * By default, returns only the item data, and in the order registered (not * sorted). You may provide one of the EXTR_* flags as an argument, allowing * the ability to return priorities or both data and priority. - * - * @param int $flag + * + * @param int $flag * @return array */ public function toArray($flag = self::EXTR_DATA) @@ -242,8 +242,8 @@ public function toArray($flag = self::EXTR_DATA) * * Please see {@link getIterator()} for details on the necessity of an * internal queue class. The class provided should extend SplPriorityQueue. - * - * @param string $class + * + * @param string $class * @return PriorityQueue */ public function setInternalQueueClass($class) @@ -254,8 +254,8 @@ public function setInternalQueueClass($class) /** * Does the queue contain the given datum? - * - * @param mixed $datum + * + * @param mixed $datum * @return bool */ public function contains($datum) @@ -270,8 +270,8 @@ public function contains($datum) /** * Does the queue have an item with the given priority? - * - * @param int $priority + * + * @param int $priority * @return bool */ public function hasPriority($priority) @@ -286,7 +286,7 @@ public function hasPriority($priority) /** * Get the inner priority queue instance - * + * * @return SplPriorityQueue */ protected function getQueue() @@ -302,4 +302,16 @@ protected function getQueue() } return $this->queue; } + + /** + * Add support for deep cloning + * + * @return void + */ + public function __clone() + { + if (null !== $this->queue) { + $this->queue = clone $this->queue; + } + } } diff --git a/test/PriorityQueueTest.php b/test/PriorityQueueTest.php index 3986ca4ff..efe464577 100644 --- a/test/PriorityQueueTest.php +++ b/test/PriorityQueueTest.php @@ -34,6 +34,11 @@ */ class PriorityQueueTest extends \PHPUnit_Framework_TestCase { + /** + * @var PriorityQueue + */ + protected $queue; + public function setUp() { $this->queue = new PriorityQueue(); @@ -132,4 +137,32 @@ public function testCanTestForExistenceOfPriorityInQueue() $this->assertTrue($this->queue->hasPriority(3)); $this->assertFalse($this->queue->hasPriority(1000)); } + + public function testCloningAlsoClonesQueue() + { + $foo = new \stdClass(); + $foo->name = 'bar'; + + $queue = new PriorityQueue(); + $queue->insert($foo, 1); + $queue->insert($foo, 2); + + $queueClone = clone $queue; + + while (!$queue->isEmpty()) { + $this->assertSame($foo, $queue->top()); + $queue->remove($queue->top()); + } + + $this->assertTrue($queue->isEmpty()); + $this->assertFalse($queueClone->isEmpty()); + $this->assertEquals(2, $queueClone->count()); + + while (!$queueClone->isEmpty()) { + $this->assertSame($foo, $queueClone->top()); + $queueClone->remove($queueClone->top()); + } + + $this->assertTrue($queueClone->isEmpty()); + } }