From 3ba68632b27d7545c939a9136736ca2a61516e64 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 15 Jul 2011 22:58:46 -0400 Subject: [PATCH] finished Vector. --- framework/base/Component.php | 272 ++++++++++++++++-------------- framework/base/Event.php | 4 +- framework/base/Exception.php | 25 +++ framework/base/Vector.php | 345 ++++++++++++++++++++++++++++++++++++++ framework/base/VectorIterator.php | 95 +++++++++++ 5 files changed, 609 insertions(+), 132 deletions(-) create mode 100644 framework/base/Exception.php create mode 100644 framework/base/Vector.php create mode 100644 framework/base/VectorIterator.php diff --git a/framework/base/Component.php b/framework/base/Component.php index 3dc4926..141ea2e 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -5,7 +5,7 @@ namespace yii\base; class Component { private $_e; - private $_m; + private $_b; /** * Returns a property value, an event handler list or a behavior based on its name. @@ -23,26 +23,27 @@ class Component public function __get($name) { $getter = 'get' . $name; - if(method_exists($this, $getter)) + if (method_exists($this, $getter)) { // read property, e.g. getName() return $this->$getter(); - else if(method_exists($this, $name) && strncasecmp($name, 'on', 2)===0) - { - $name=strtolower($name); - if(!isset($this->_e[$name])) - $this->_e[$name]=new yii\collections\Vector; + } + elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event, e.g. onClick() + $name = strtolower($name); + if (!isset($this->_e[$name])) { + $this->_e[$name] = new \yii\collections\Vector; + } return $this->_e[$name]; } - else if(isset($this->_m[$name])) - return $this->_m[$name]; - else if(is_array($this->_m)) // has attached behaviors - { - foreach($this->_m as $object) - { - if($object->getEnabled() && $object->canGetProperty($name)) + elseif (isset($this->_b[$name])) { // behavior + return $this->_b[$name]; + } + elseif (is_array($this->_b)) { // a behavior property + foreach ($this->_b as $object) { + if ($object->getEnabled() && $object->canGetProperty($name)) { return $object->$name; + } } } - throw new Exception('Undefined property: ' . get_class($this) . '.' $name); + throw new Exception('Getting unknown property: ' . get_class($this) . '.' $name); } /** @@ -58,30 +59,32 @@ class Component * @throws CException if the property/event is not defined or the property is read only. * @see __get */ - public function __set($name,$value) + public function __set($name, $value) { - $setter='set'.$name; - if(method_exists($this,$setter)) + $setter = 'set' . $name; + if (method_exists($this, $setter)) { return $this->$setter($value); - else if(method_exists($this,$name) && strncasecmp($name,'on',2)===0) - { - $name=strtolower($name); - if(!isset($this->_e[$name])) - $this->_e[$name]=new yii\collections\Vector; + } + elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { + $name = strtolower($name); + if (!isset($this->_e[$name])) { + $this->_e[$name] = new \yii\collections\Vector; + } return $this->_e[$name]->add($value); } - else if(is_array($this->_m)) - { - foreach($this->_m as $object) - { - if($object->getEnabled() && $object->canSetProperty($name)) - return $object->$name=$value; + elseif (is_array($this->_b)) { + foreach ($this->_b as $object) { + if ($object->getEnabled() && $object->canSetProperty($name)) { + return $object->$name = $value; + } } } - if(method_exists($this,'get'.$name)) - throw new Exception('Unable to set read-only property: ' . get_class($this) . '.' $name); - else - throw new Exception('Undefined property: ' . get_class($this) . '.' $name); + if (method_exists($this, 'get' . $name)) { + throw new Exception('Setting read-only property: ' . get_class($this) . '.' $name); + } + else { + throw new Exception('Setting unknown property: ' . get_class($this) . '.' $name); + } } /** @@ -93,22 +96,22 @@ class Component */ public function __isset($name) { - $getter='get'.$name; - if(method_exists($this,$getter)) - return $this->$getter()!==null; - else if(method_exists($this,$name) && strncasecmp($name,'on',2)===0) - { - $name=strtolower($name); + $getter = 'get' . $name; + if (method_exists($this, $getter)) { // property is not null + return $this->$getter() !== null; + } + elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // has event handler + $name = strtolower($name); return isset($this->_e[$name]) && $this->_e[$name]->getCount(); } - else if(isset($this->_m[$name])) + elseif (isset($this->_b[$name])) { // has behavior return true; - else if(is_array($this->_m)) - { - foreach($this->_m as $object) - { - if($object->getEnabled() && $object->canGetProperty($name)) - return true; + } + elseif (is_array($this->_b)) { + foreach ($this->_b as $object) { + if ($object->getEnabled() && $object->canGetProperty($name)) { + return $object->$name !== null; + } } } return false; @@ -124,23 +127,26 @@ class Component */ public function __unset($name) { - $setter='set'.$name; - if(method_exists($this,$setter)) + $setter = 'set' . $name; + if (method_exists($this, $setter)) { $this->$setter(null); - else if(method_exists($this,$name) && strncasecmp($name,'on',2)===0) + } + elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { unset($this->_e[strtolower($name)]); - else if(isset($this->_m[$name])) + } + elseif (isset($this->_b[$name])) { $this->detachBehavior($name); - else if(is_array($this->_m)) - { - foreach($this->_m as $object) + } + elseif (is_array($this->_b)) { + foreach ($this->_b as $object) { - if($object->getEnabled() && $object->canSetProperty($name)) - return $object->$name=null; + if ($object->getEnabled() && $object->canSetProperty($name)) { + return $object->$name = null; + } } } - else if(method_exists($this,'get'.$name)) - throw new Exception('Unable to unset read-only property: ' . get_class($this) . '.' $name); + elseif (method_exists($this, 'get' . $name)) + throw new Exception('Unsetting read-only property: ' . get_class($this) . '.' $name); } /** @@ -152,18 +158,23 @@ class Component * @return mixed the method return value * @since 1.0.2 */ - public function __call($name,$parameters) + public function __call($name, $parameters) { - if($this->_m!==null) + if ($this->_b !== null) { - foreach($this->_m as $object) + foreach ($this->_b as $object) { - if($object->getEnabled() && method_exists($object,$name)) - return call_user_func_array(array($object,$name),$parameters); + if ($object->getEnabled() && method_exists($object, $name)) { + return call_user_func_array(array($object, $name), $parameters); + } + } + } + if ($this->canGetProperty($name)) { + $func = $this->$name; + if ($func instanceof \Closure) { + return call_user_func_array($func, $parameters); } } - if($this->canGetProperty($name) && $this->$name instanceof \Closure) - return call_user_func_array($this->$name, $parameters); throw new Exception('Unknown method: ' . get_class($this) . '::' $name . '()'); } @@ -176,7 +187,7 @@ class Component */ public function asa($behavior) { - return isset($this->_m[$behavior]) ? $this->_m[$behavior] : null; + return isset($this->_b[$behavior]) ? $this->_b[$behavior] : null; } /** @@ -196,8 +207,8 @@ class Component */ public function attachBehaviors($behaviors) { - foreach($behaviors as $name=>$behavior) - $this->attachBehavior($name,$behavior); + foreach ($behaviors as $name => $behavior) + $this->attachBehavior($name, $behavior); } /** @@ -206,11 +217,11 @@ class Component */ public function detachBehaviors() { - if($this->_m!==null) + if ($this->_b !== null) { - foreach($this->_m as $name=>$behavior) + foreach ($this->_b as $name => $behavior) $this->detachBehavior($name); - $this->_m=null; + $this->_b = null; } } @@ -225,13 +236,13 @@ class Component * @return IBehavior the behavior object * @since 1.0.2 */ - public function attachBehavior($name,$behavior) + public function attachBehavior($name, $behavior) { - if(!($behavior instanceof IBehavior)) - $behavior=Yii::createComponent($behavior); + if (!($behavior instanceof IBehavior)) + $behavior = Yii::createComponent($behavior); $behavior->setEnabled(true); $behavior->attach($this); - return $this->_m[$name]=$behavior; + return $this->_b[$name] = $behavior; } /** @@ -243,11 +254,11 @@ class Component */ public function detachBehavior($name) { - if(isset($this->_m[$name])) + if (isset($this->_b[$name])) { - $this->_m[$name]->detach($this); - $behavior=$this->_m[$name]; - unset($this->_m[$name]); + $this->_b[$name]->detach($this); + $behavior = $this->_b[$name]; + unset($this->_b[$name]); return $behavior; } } @@ -258,9 +269,9 @@ class Component */ public function enableBehaviors() { - if($this->_m!==null) + if ($this->_b !== null) { - foreach($this->_m as $behavior) + foreach ($this->_b as $behavior) $behavior->setEnabled(true); } } @@ -271,9 +282,9 @@ class Component */ public function disableBehaviors() { - if($this->_m!==null) + if ($this->_b !== null) { - foreach($this->_m as $behavior) + foreach ($this->_b as $behavior) $behavior->setEnabled(false); } } @@ -287,8 +298,8 @@ class Component */ public function enableBehavior($name) { - if(isset($this->_m[$name])) - $this->_m[$name]->setEnabled(true); + if (isset($this->_b[$name])) + $this->_b[$name]->setEnabled(true); } /** @@ -299,8 +310,8 @@ class Component */ public function disableBehavior($name) { - if(isset($this->_m[$name])) - $this->_m[$name]->setEnabled(false); + if (isset($this->_b[$name])) + $this->_b[$name]->setEnabled(false); } /** @@ -308,13 +319,14 @@ class Component * A property is defined if there is a getter or setter method * defined in the class. Note, property names are case-insensitive. * @param string $name the property name + * @param boolean $checkVar whether to check class properties. If false, only properties declared by getters will be checked. * @return boolean whether the property is defined * @see canGetProperty * @see canSetProperty */ - public function hasProperty($name) + public function hasProperty($name, $checkVar = true) { - return method_exists($this,'get'.$name) || method_exists($this,'set'.$name); + return method_exists($this, 'get' . $name) || method_exists($this, 'set' . $name) || property_exists($this, $name); } /** @@ -326,9 +338,9 @@ class Component * @return boolean whether the property can be read * @see canSetProperty */ - public function canGetProperty($name, $checkVar=true) + public function canGetProperty($name, $checkVar = true) { - return method_exists($this,'get'.$name) || $checkVar && property_exists($this,$name); + return method_exists($this, 'get' . $name) || $checkVar && property_exists($this, $name); } /** @@ -340,9 +352,9 @@ class Component * @return boolean whether the property can be written * @see canGetProperty */ - public function canSetProperty($name, $checkVar=true) + public function canSetProperty($name, $checkVar = true) { - return method_exists($this,'set'.$name) || $checkVar && property_exists($this,$name); + return method_exists($this, 'set' . $name) || $checkVar && property_exists($this, $name); } /** @@ -354,7 +366,7 @@ class Component */ public function hasEvent($name) { - return !strncasecmp($name,'on',2) && method_exists($this,$name); + return !strncasecmp($name, 'on', 2) && method_exists($this, $name); } /** @@ -364,8 +376,8 @@ class Component */ public function hasEventHandler($name) { - $name=strtolower($name); - return isset($this->_e[$name]) && $this->_e[$name]->getCount()>0; + $name = strtolower($name); + return isset($this->_e[$name]) && $this->_e[$name]->getCount() > 0; } /** @@ -376,16 +388,16 @@ class Component */ public function getEventHandlers($name) { - if($this->hasEvent($name)) + if ($this->hasEvent($name)) { - $name=strtolower($name); - if(!isset($this->_e[$name])) - $this->_e[$name]=new CList; + $name = strtolower($name); + if (!isset($this->_e[$name])) + $this->_e[$name] = new CList; return $this->_e[$name]; } else - throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.', - array('{class}'=>get_class($this), '{event}'=>$name))); + throw new CException(Yii::t('yii', 'Event "{class}.{event}" is not defined.', + array('{class}' => get_class($this), '{event}' => $name))); } /** @@ -420,7 +432,7 @@ class Component * @throws CException if the event is not defined * @see detachEventHandler */ - public function attachEventHandler($name,$handler) + public function attachEventHandler($name, $handler) { $this->getEventHandlers($name)->add($handler); } @@ -433,10 +445,10 @@ class Component * @return boolean if the detachment process is successful * @see attachEventHandler */ - public function detachEventHandler($name,$handler) + public function detachEventHandler($name, $handler) { - if($this->hasEventHandler($name)) - return $this->getEventHandlers($name)->remove($handler)!==false; + if ($this->hasEventHandler($name)) + return $this->getEventHandlers($name)->remove($handler) !== false; else return false; } @@ -449,43 +461,43 @@ class Component * @param CEvent $event the event parameter * @throws CException if the event is undefined or an event handler is invalid. */ - public function raiseEvent($name,$event) + public function raiseEvent($name, $event) { - $name=strtolower($name); - if(isset($this->_e[$name])) + $name = strtolower($name); + if (isset($this->_e[$name])) { - foreach($this->_e[$name] as $handler) + foreach ($this->_e[$name] as $handler) { - if(is_string($handler)) - call_user_func($handler,$event); - else if(is_callable($handler,true)) + if (is_string($handler)) + call_user_func($handler, $event); + elseif (is_callable($handler, true)) { - if(is_array($handler)) + if (is_array($handler)) { // an array: 0 - object, 1 - method name - list($object,$method)=$handler; - if(is_string($object)) // static method call - call_user_func($handler,$event); - else if(method_exists($object,$method)) + list($object, $method) = $handler; + if (is_string($object)) // static method call + call_user_func($handler, $event); + elseif (method_exists($object, $method)) $object->$method($event); else - throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".', - array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1]))); + throw new CException(Yii::t('yii', 'Event "{class}.{event}" is attached with an invalid handler "{handler}".', + array('{class}' => get_class($this), '{event}' => $name, '{handler}' => $handler[1]))); } else // PHP 5.3: anonymous function - call_user_func($handler,$event); + call_user_func($handler, $event); } else - throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".', - array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler)))); + throw new CException(Yii::t('yii', 'Event "{class}.{event}" is attached with an invalid handler "{handler}".', + array('{class}' => get_class($this), '{event}' => $name, '{handler}' => gettype($handler)))); // stop further handling if param.handled is set true - if(($event instanceof CEvent) && $event->handled) + if (($event instanceof CEvent) && $event->handled) return; } } - else if(YII_DEBUG && !$this->hasEvent($name)) - throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.', - array('{class}'=>get_class($this), '{event}'=>$name))); + elseif (YII_DEBUG && !$this->hasEvent($name)) + throw new CException(Yii::t('yii', 'Event "{class}.{event}" is not defined.', + array('{class}' => get_class($this), '{event}' => $name))); } /** @@ -510,16 +522,16 @@ class Component * @return mixed the expression result * @since 1.1.0 */ - public function evaluateExpression($_expression_,$_data_=array()) + public function evaluateExpression($_expression_, $_data_ = array()) { - if(is_string($_expression_)) + if (is_string($_expression_)) { extract($_data_); - return eval('return '.$_expression_.';'); + return eval('return ' . $_expression_ . ';'); } else { - $_data_[]=$this; + $_data_[] = $this; return call_user_func_array($_expression_, $_data_); } } diff --git a/framework/base/Event.php b/framework/base/Event.php index e95888d..5a479a0 100644 --- a/framework/base/Event.php +++ b/framework/base/Event.php @@ -3,7 +3,7 @@ namespace yii\base; /** - * CEvent is the base class for all event classes. + * Event is the base class for all event classes. * * It encapsulates the parameters associated with an event. * The {@link sender} property describes who raises the event. @@ -16,7 +16,7 @@ namespace yii\base; * @package system.base * @since 1.0 */ -class CEvent extends CComponent +class Event extends Component { /** * @var object the sender of this event diff --git a/framework/base/Exception.php b/framework/base/Exception.php new file mode 100644 index 0000000..dc2389c --- /dev/null +++ b/framework/base/Exception.php @@ -0,0 +1,25 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * Exception represents a generic exception for all purposes. + * + * @author Qiang Xue + * @version $Id: CException.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.base + * @since 1.0 + */ +class Exception extends \Exception +{ +} + diff --git a/framework/base/Vector.php b/framework/base/Vector.php new file mode 100644 index 0000000..fe35fca --- /dev/null +++ b/framework/base/Vector.php @@ -0,0 +1,345 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2012 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +namespace yii\base; + +/** + * Vector implements an integer-indexed collection class. + * + * You can access, append, insert, remove an item from the vector + * by calling methods such as [[itemAt]], [[add]], [[insertAt]], + * [[remove]] and [[removeAt]]. + * + * To get the number of the items in the vector, use [[getCount]]. + * + * Because Vector implements a set of SPL interfaces, it can be used + * like a regular PHP array as follows, + * + * ~~~php + * $vector[] = $item; // append new item at the end + * $vector[$index] = $item; // set new item at $index + * unset($vector[$index]); // remove the item at $index + * if (isset($vector[$index])) // if the vector has an item at $index + * foreach ($vector as $index=>$item) // traverse each item in the vector + * $n = count($vector); // count the number of items + * ~~~ + * + * Note that if you plan to extend Vector by performing additional operations + * with each addition or removal of an item (e.g. performing type check), + * please make sure you override [[insertAt]] and [[removeAt]]. + * + * @author Qiang Xue + * @since 2.0 + */ +class Vector extends Component implements \IteratorAggregate, \ArrayAccess, \Countable +{ + /** + * @var boolean whether this vector is read-only or not. + * If the vector is read-only, adding or moving items will throw an exception. + */ + public $readOnly; + /** + * @var array internal data storage + */ + private $_d = array(); + /** + * @var integer number of items + */ + private $_c = 0; + + /** + * Constructor. + * Initializes the vector with an array or an iterable object. + * @param mixed $data the initial data to be populated into the vector. + * This can be an array or an iterable object. If null, the vector will be set as empty. + * @param boolean $readOnly whether the vector should be marked as read-only. + * @throws Exception if data is not well formed (neither an array nor an iterable object) + */ + public function __construct($data = array(), $readOnly = false) + { + if ($data !== array()) { + $this->copyFrom($data); + } + $this->readOnly = $readOnly; + } + + /** + * Returns an iterator for traversing the items in the vector. + * This method is required by the SPL interface `IteratorAggregate`. + * It will be implicitly called when you use `foreach` to traverse the vector. + * @return Iterator an iterator for traversing the items in the vector. + */ + public function getIterator() + { + return new VectorIterator($this->_d); + } + + /** + * Returns the number of items in the vector. + * This method is required by the SPL `Countable` interface. + * It will be implicitly called when you use `count($vector)`. + * @return integer number of items in the vector. + */ + public function count() + { + return $this->getCount(); + } + + /** + * Returns the number of items in the vector. + * @return integer the number of items in the vector + */ + public function getCount() + { + return $this->_c; + } + + /** + * Returns the item at the specified index. + * @param integer $index the index of the item + * @return mixed the item at the index + * @throws Exception if the index is out of range + */ + public function itemAt($index) + { + if (isset($this->_d[$index])) { + return $this->_d[$index]; + } + elseif ($index >= 0 && $index < $this->_c) { // in case the value is null + return $this->_d[$index]; + } + + throw new Exception('Index out of range: ' . $index); + } + + /** + * Appends an item at the end of the vector. + * @param mixed $item new item + * @return integer the zero-based index at which the item is added + * @throws Exception if the vector is read-only. + */ + public function add($item) + { + $this->insertAt($this->_c, $item); + return $this->_c-1; + } + + /** + * Inserts an item at the specified position. + * Original item at the position and the following items will be moved + * one step towards the end. + * @param integer $index the specified position. + * @param mixed $item new item to be inserted into the vector + * @throws Exception if the index specified is out of range, or the vector is read-only. + */ + public function insertAt($index, $item) + { + if (!$this->readOnly) { + if ($index === $this->_c) { + $this->_d[$this->_c++] = $item; + } + elseif ($index >= 0 && $index < $this->_c) { + array_splice($this->_d, $index, 0, array($item)); + $this->_c++; + } + throw new Exception('Index out of range: ' . $index); + } + throw new Exception('Vector is read only.'); + } + + /** + * Removes an item from the vector. + * The vector will search for the item, and the first item found + * will be removed from the vector. + * @param mixed $item the item to be removed. + * @return mixed the index at which the item is being removed, or false + * if the item cannot be found in the vector. + * @throws Exception if the vector is read only. + */ + public function remove($item) + { + if (($index = $this->indexOf($item)) >= 0) + { + $this->removeAt($index); + return $index; + } + else + return false; + } + + /** + * Removes an item at the specified position. + * @param integer $index the index of the item to be removed. + * @return mixed the removed item. + * @throws Exception if the index is out of range, or the vector is read only. + */ + public function removeAt($index) + { + if (!$this->readOnly) { + if ($index >= 0 && $index < $this->_c) { + $this->_c--; + if ($index === $this->_c) { + return array_pop($this->_d); + } + else { + $item = $this->_d[$index]; + array_splice($this->_d, $index, 1); + return $item; + } + } + throw new Exception('Index out of range: ' . $index); + } + throw new Exception('Vector is read only.'); + } + + /** + * Removes all items from the vector. + */ + public function clear() + { + for ($i = $this->_c-1;$i >= 0;--$i) { + $this->removeAt($i); + } + } + + /** + * Returns a value indicating whether the vector contains the specified item. + * Note that the search is based on strict PHP comparison. + * @param mixed $item the item + * @return boolean whether the vector contains the item + */ + public function contains($item) + { + return $this->indexOf($item) >= 0; + } + + /** + * Returns the index of the specified item in the vector. + * The index is zero-based. If the item is not found in the vector, -1 will be returned. + * Note that the search is based on strict PHP comparison. + * @param mixed $item the item + * @return integer the index of the item in the vector (0 based), -1 if not found. + */ + public function indexOf($item) + { + $index = array_search($item, $this->_d, true); + return $index === false ? -1 : $index; + } + + /** + * Returns the vector as a PHP array. + * @return array the items in the vector. + */ + public function toArray() + { + return $this->_d; + } + + /** + * Copies iterable data into the vector. + * Note, existing data in the vector will be cleared first. + * @param mixed $data the data to be copied from, must be an array or an object implementing `Traversable` + * @throws Exception if data is neither an array nor an object implementing `Traversable`. + */ + public function copyFrom($data) + { + if (is_array($data) || ($data instanceof Traversable)) { + if ($this->_c > 0) { + $this->clear(); + } + if ($data instanceof self) { + $data = $data->_d; + } + foreach ($data as $item) { + $this->add($item); + } + } + throw new Exception('Data must be either an array or an object implementing Traversable.'); + } + + /** + * Merges iterable data into the vector. + * New items will be appended to the end of the existing items. + * @param mixed $data the data to be merged with, must be an array or an object implementing `Traversable` + * @throws Exception if data is neither an array nor an object implementing `Traversable`. + */ + public function mergeWith($data) + { + if (is_array($data) || ($data instanceof Traversable)) { + if ($data instanceof Vector) { + $data = $data->_d; + } + foreach ($data as $item) { + $this->add($item); + } + } + throw new Exception('Data must be either an array or an object implementing Traversable.'); + } + + /** + * Returns a value indicating whether there is an item at the specified offset. + * This method is required by the SPL interface `ArrayAccess`. + * It is implicitly called when you use something like `isset($vector[$index])`. + * @param integer $offset the offset to be checked + * @return boolean whether there is an item at the specified offset. + */ + public function offsetExists($offset) + { + return $offset >= 0 && $offset < $this->_c; + } + + /** + * Returns the item at the specified offset. + * This method is required by the SPL interface `ArrayAccess`. + * It is implicitly called when you use something like `$value = $vector[$index];`. + * @param integer $offset the offset to retrieve item. + * @return mixed the item at the offset + * @throws Exception if the offset is out of range + */ + public function offsetGet($offset) + { + return $this->itemAt($offset); + } + + /** + * Sets the item at the specified offset. + * This method is required by the SPL interface `ArrayAccess`. + * It is implicitly called when you use something like `$vector[$index] = $value;`. + * If the offset is null or equal to the number of the existing items, + * the new item will be appended to the vector. + * Otherwise, the existing item at the offset will be replaced with the new item. + * @param integer $offset the offset to set item + * @param mixed $item the item value + * @throws Exception if the offset is out of range, or the vector is read only. + */ + public function offsetSet($offset, $item) + { + if ($offset === null || $offset === $this->_c) { + $this->insertAt($this->_c, $item); + } + else { + $this->removeAt($offset); + $this->insertAt($offset, $item); + } + } + + /** + * Unsets the item at the specified offset. + * This method is required by the SPL interface `ArrayAccess`. + * It is implicitly called when you use something like `unset($vector[$index])`. + * This is equivalent to [[removeAt]]. + * @param integer $offset the offset to unset item + * @throws Exception if the offset is out of range, or the vector is read only. + */ + public function offsetUnset($offset) + { + $this->removeAt($offset); + } +} diff --git a/framework/base/VectorIterator.php b/framework/base/VectorIterator.php new file mode 100644 index 0000000..6abf674 --- /dev/null +++ b/framework/base/VectorIterator.php @@ -0,0 +1,95 @@ + + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2012 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +namespace yii\base; + +/** + * VectorIterator implements the SPL `Iterator` interface for [[Vector]]. + * + * It allows [[Vector]] to return a new iterator for data traversing purpose. + * You normally do not use this class directly. + * + * @author Qiang Xue + * @since 2.0 + */ +class VectorIterator implements \Iterator +{ + /** + * @var array the data to be iterated through + */ + private $_d; + /** + * @var integer index of the current item + */ + private $_i; + /** + * @var integer count of the data items + */ + private $_c; + + /** + * Constructor. + * @param array $data the data to be iterated through + */ + public function __construct(&$data) + { + $this->_d = &$data; + $this->_i = 0; + $this->_c = count($this->_d); + } + + /** + * Rewinds the index of the current item. + * This method is required by the SPL interface `Iterator`. + */ + public function rewind() + { + $this->_i = 0; + } + + /** + * Returns the key of the current item. + * This method is required by the SPL interface `Iterator`. + * @return integer the key of the current item + */ + public function key() + { + return $this->_i; + } + + /** + * Returns the current item. + * This method is required by the SPL interface `Iterator`. + * @return mixed the current item + */ + public function current() + { + return $this->_d[$this->_i]; + } + + /** + * Moves the internal pointer to the next item. + * This method is required by the SPL interface `Iterator`. + */ + public function next() + { + $this->_i++; + } + + /** + * Returns a value indicating whether there is an item at current position. + * This method is required by the SPL interface `Iterator`. + * @return boolean whether there is an item at current position. + */ + public function valid() + { + return $this->_i < $this->_c; + } +}