File indexing completed on 2024-05-12 06:03:07

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Stdlib
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  */
0020 
0021 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
0022     /**
0023      * SplPriorityQueue 
0024      *
0025      * PHP 5.2.X userland implementation of PHP's SplPriorityQueue
0026      */
0027     class SplPriorityQueue implements Iterator , Countable 
0028     {
0029         /**
0030          * Extract data only
0031          */
0032         const EXTR_DATA = 0x00000001;
0033 
0034         /**
0035          * Extract priority only
0036          */
0037         const EXTR_PRIORITY = 0x00000002;
0038 
0039         /**
0040          * Extract an array of ('data' => $value, 'priority' => $priority)
0041          */
0042         const EXTR_BOTH = 0x00000003;
0043 
0044         /**
0045          * Count of items in the queue
0046          * @var int
0047          */
0048         protected $count = 0;
0049 
0050         /**
0051          * Flag indicating what should be returned when iterating or extracting
0052          * @var int
0053          */
0054         protected $extractFlags = self::EXTR_DATA;
0055 
0056         /**
0057          * @var bool|array
0058          */
0059         protected $preparedQueue = false;
0060 
0061         /**
0062          * All items in the queue
0063          * @var array
0064          */
0065         protected $queue = array();
0066 
0067         /**
0068          * Constructor
0069          * 
0070          * Creates a new, empty queue
0071          * 
0072          * @return void
0073          */
0074         public function __construct()
0075         {
0076         }
0077 
0078         /**
0079          * Compare two priorities
0080          *
0081          * Returns positive integer if $priority1 is greater than $priority2, 0 
0082          * if equal, negative otherwise.
0083          *
0084          * Unused internally, and only included in order to retain the same 
0085          * interface as PHP's SplPriorityQueue.
0086          *
0087          * @param  mixed $priority1
0088          * @param  mixed $priority2
0089          * @return int
0090          */
0091         public function compare($priority1, $priority2)
0092         {
0093             if ($priority1 > $priority2) {
0094                 return 1;
0095             }
0096             if ($priority1 == $priority2) {
0097                 return 0;
0098             }
0099 
0100             return -1;
0101         }
0102 
0103         /**
0104          * Countable: return number of items composed in the queue
0105          * 
0106          * @return int
0107          */
0108         public function count()
0109         {
0110             return $this->count;
0111         }
0112 
0113         /**
0114          * Iterator: return current item
0115          *
0116          * @return mixed
0117          */
0118         public function current()
0119         {
0120             if (!$this->preparedQueue) {
0121                 $this->rewind();
0122             }
0123             if (!$this->count) {
0124                 throw new OutOfBoundsException('Cannot iterate SplPriorityQueue; no elements present');
0125             }
0126 
0127 if (!is_array($this->preparedQueue)) {
0128     throw new DomainException(sprintf(
0129         "Queue was prepared, but is empty?\n    PreparedQueue: %s\n    Internal Queue: %s\n",
0130         var_export($this->preparedQueue, 1),
0131         var_export($this->queue, 1)
0132     ));
0133 }
0134 
0135             $return      = array_shift($this->preparedQueue);
0136             $priority    = $return['priority'];
0137             $priorityKey = $return['priorityKey'];
0138             $key         = $return['key'];
0139             unset($return['key']);
0140             unset($return['priorityKey']);
0141             unset($this->queue[$priorityKey][$key]);
0142 
0143             switch ($this->extractFlags) {
0144                 case self::EXTR_DATA:
0145                     return $return['data'];
0146                 case self::EXTR_PRIORITY:
0147                     return $return['priority'];
0148                 case self::EXTR_BOTH:
0149                 default:
0150                     return $return;
0151             };
0152         }
0153 
0154         /**
0155          * Extract a node from top of the heap and sift up
0156          *
0157          * Returns either the value, the priority, or both, depending on the extract flag.
0158          *
0159          * @return mixed;
0160          */
0161         public function extract()
0162         {
0163             if (!$this->count) {
0164                 return null;
0165             }
0166 
0167             if (!$this->preparedQueue) {
0168                 $this->prepareQueue();
0169             }
0170 
0171             if (empty($this->preparedQueue)) {
0172                 return null;
0173             }
0174 
0175             $return      = array_shift($this->preparedQueue);
0176             $priority    = $return['priority'];
0177             $priorityKey = $return['priorityKey'];
0178             $key         = $return['key'];
0179             unset($return['key']);
0180             unset($return['priorityKey']);
0181             unset($this->queue[$priorityKey][$key]);
0182             $this->count--;
0183 
0184             switch ($this->extractFlags) {
0185                 case self::EXTR_DATA:
0186                     return $return['data'];
0187                 case self::EXTR_PRIORITY:
0188                     return $return['priority'];
0189                 case self::EXTR_BOTH:
0190                 default:
0191                     return $return;
0192             };
0193         }
0194 
0195         /**
0196          * Insert a value into the heap, at the specified priority
0197          *
0198          * @param  mixed $value
0199          * @param  mixed $priority
0200          * @return void
0201          */
0202         public function insert($value, $priority)
0203         {
0204             if (!is_scalar($priority)) {
0205                 $priority = serialize($priority);
0206             }
0207             if (!isset($this->queue[$priority])) {
0208                 $this->queue[$priority] = array();
0209             }
0210             $this->queue[$priority][] = $value;
0211             $this->count++;
0212             $this->preparedQueue = false;
0213         }
0214 
0215         /**
0216          * Is the queue currently empty?
0217          *
0218          * @return bool
0219          */
0220         public function isEmpty()
0221         {
0222             return (0 == $this->count);
0223         }
0224 
0225         /**
0226          * Iterator: return current key
0227          *
0228          * @return mixed Usually an int or string
0229          */
0230         public function key()
0231         {
0232             return $this->count;
0233         }
0234 
0235         /**
0236          * Iterator: Move pointer forward
0237          *
0238          * @return void
0239          */
0240         public function next()
0241         {
0242             $this->count--;
0243         }
0244 
0245         /**
0246          * Recover from corrupted state and allow further actions on the queue
0247          *
0248          * Unimplemented, and only included in order to retain the same interface as PHP's 
0249          * SplPriorityQueue.
0250          *
0251          * @return void
0252          */
0253         public function recoverFromCorruption()
0254         {
0255         }
0256 
0257         /**
0258          * Iterator: Move pointer to first item
0259          *
0260          * @return void
0261          */
0262         public function rewind()
0263         {
0264             if (!$this->preparedQueue) {
0265                 $this->prepareQueue();
0266             }
0267         }
0268 
0269         /**
0270          * Set the extract flags
0271          * 
0272          * Defines what is extracted by SplPriorityQueue::current(), 
0273          * SplPriorityQueue::top() and SplPriorityQueue::extract().
0274          * 
0275          * - SplPriorityQueue::EXTR_DATA (0x00000001): Extract the data
0276          * - SplPriorityQueue::EXTR_PRIORITY (0x00000002): Extract the priority
0277          * - SplPriorityQueue::EXTR_BOTH (0x00000003): Extract an array containing both
0278          *
0279          * The default mode is SplPriorityQueue::EXTR_DATA.
0280          *
0281          * @param  int $flags
0282          * @return void
0283          */
0284         public function setExtractFlags($flags)
0285         {
0286             $expected = array(
0287                 self::EXTR_DATA => true,
0288                 self::EXTR_PRIORITY => true,
0289                 self::EXTR_BOTH => true,
0290             );
0291             if (!isset($expected[$flags])) {
0292                 throw new InvalidArgumentException(sprintf('Expected an EXTR_* flag; received %s', $flags));
0293             }
0294             $this->extractFlags = $flags;
0295         }
0296 
0297         /**
0298          * Return the value or priority (or both) of the top node, depending on 
0299          * the extract flag
0300          *
0301          * @return mixed
0302          */
0303         public function top()
0304         {
0305             $this->sort();
0306             $keys = array_keys($this->queue);
0307             $key  = array_shift($keys);
0308             if (preg_match('/^(a|O):/', $key)) {
0309                 $key = unserialize($key);
0310             }
0311 
0312             if ($this->extractFlags == self::EXTR_PRIORITY) {
0313                 return $key;
0314             }
0315 
0316             if ($this->extractFlags == self::EXTR_DATA) {
0317                 return $this->queue[$key][0];
0318             }
0319 
0320             return array(
0321                 'data'     => $this->queue[$key][0],
0322                 'priority' => $key,
0323             );
0324         }
0325 
0326         /**
0327          * Iterator: is the current position valid for the queue
0328          *
0329          * @return bool
0330          */
0331         public function valid()
0332         {
0333             return (bool) $this->count;
0334         }
0335 
0336         /**
0337          * Sort the queue
0338          * 
0339          * @return void
0340          */
0341         protected function sort()
0342         {
0343             krsort($this->queue);
0344         }
0345 
0346         /**
0347          * Prepare the queue for iteration and/or extraction
0348          * 
0349          * @return void
0350          */
0351         protected function prepareQueue()
0352         {
0353             $this->sort();
0354             $count = $this->count;
0355             $queue = array();
0356             foreach ($this->queue as $priority => $values) {
0357                 $priorityKey = $priority;
0358                 if (preg_match('/^(a|O):/', $priority)) {
0359                     $priority = unserialize($priority);
0360                 }
0361                 foreach ($values as $key => $value) {
0362                     $queue[$count] = array(
0363                         'data'        => $value,
0364                         'priority'    => $priority,
0365                         'priorityKey' => $priorityKey,
0366                         'key'         => $key,
0367                     );
0368                     $count--;
0369                 }
0370             }
0371             $this->preparedQueue = $queue;
0372         }
0373     }
0374 }
0375 
0376 /**
0377  * Serializable version of SplPriorityQueue
0378  *
0379  * Also, provides predictable heap order for datums added with the same priority
0380  * (i.e., they will be emitted in the same order they are enqueued).
0381  *
0382  * @category   Zend
0383  * @package    Zend_Stdlib
0384  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0385  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0386  */
0387 class Zend_Stdlib_SplPriorityQueue extends SplPriorityQueue implements Serializable
0388 {
0389     /**
0390      * @var int Seed used to ensure queue order for items of the same priority
0391      */
0392     protected $serial = PHP_INT_MAX;
0393 
0394     /**
0395      * @var bool
0396      */
0397     protected $isPhp53;
0398 
0399     /**
0400      * Constructor
0401      * 
0402      * @return void
0403      */
0404     public function __construct()
0405     {
0406         $this->isPhp53 = version_compare(PHP_VERSION, '5.3', '>=');
0407     }
0408 
0409     /**
0410      * Insert a value with a given priority
0411      *
0412      * Utilizes {@var $serial} to ensure that values of equal priority are 
0413      * emitted in the same order in which they are inserted.
0414      * 
0415      * @param  mixed $datum 
0416      * @param  mixed $priority 
0417      * @return void
0418      */
0419     public function insert($datum, $priority)
0420     {
0421         // If using the native PHP SplPriorityQueue implementation, we need to
0422         // hack around it to ensure that items registered at the same priority
0423         // return in the order registered. In the userland version, this is not
0424         // necessary.
0425         if ($this->isPhp53) {
0426             if (!is_array($priority)) {
0427                 $priority = array($priority, $this->serial--);
0428             }
0429         }
0430         parent::insert($datum, $priority);
0431     }
0432 
0433     /**
0434      * Serialize to an array
0435      *
0436      * Array will be priority => data pairs
0437      * 
0438      * @return array
0439      */
0440     public function toArray()
0441     {
0442         $this->setExtractFlags(self::EXTR_BOTH);
0443         $array = array();
0444         while ($this->valid()) {
0445             $array[] = $this->current();
0446             $this->next();
0447         }
0448         $this->setExtractFlags(self::EXTR_DATA);
0449 
0450         // Iterating through a priority queue removes items
0451         foreach ($array as $item) {
0452             $this->insert($item['data'], $item['priority']);
0453         }
0454 
0455         // Return only the data
0456         $return = array();
0457         foreach ($array as $item) {
0458             $return[] = $item['data'];
0459         }
0460 
0461         return $return;
0462     }
0463 
0464     /**
0465      * Serialize
0466      * 
0467      * @return string
0468      */
0469     public function serialize()
0470     {
0471         $data = array();
0472         $this->setExtractFlags(self::EXTR_BOTH);
0473         while ($this->valid()) {
0474             $data[] = $this->current();
0475             $this->next();
0476         }
0477         $this->setExtractFlags(self::EXTR_DATA);
0478 
0479         // Iterating through a priority queue removes items
0480         foreach ($data as $item) {
0481             $this->insert($item['data'], $item['priority']);
0482         }
0483 
0484         return serialize($data);
0485     }
0486 
0487     /**
0488      * Deserialize
0489      * 
0490      * @param  string $data
0491      * @return void
0492      */
0493     public function unserialize($data)
0494     {
0495         foreach (unserialize($data) as $item) {
0496             $this->insert($item['data'], $item['priority']);
0497         }
0498     }
0499 }