Browse Source

finished Vector.

tags/2.0.0-beta
Qiang Xue 13 years ago
parent
commit
3ba68632b2
  1. 272
      framework/base/Component.php
  2. 4
      framework/base/Event.php
  3. 25
      framework/base/Exception.php
  4. 345
      framework/base/Vector.php
  5. 95
      framework/base/VectorIterator.php

272
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,23 +96,23 @@ 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]))
return true;
else if(is_array($this->_m))
{
foreach($this->_m as $object)
{
if($object->getEnabled() && $object->canGetProperty($name))
elseif (isset($this->_b[$name])) { // has behavior
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_);
}
}

4
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

25
framework/base/Exception.php

@ -0,0 +1,25 @@
<?php
namespace yii\base;
/**
* Exception class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* Exception represents a generic exception for all purposes.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id: CException.php 2799 2011-01-01 19:31:13Z qiang.xue $
* @package system.base
* @since 1.0
*/
class Exception extends \Exception
{
}

345
framework/base/Vector.php

@ -0,0 +1,345 @@
<?php
/**
* Vector class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 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 <qiang.xue@gmail.com>
* @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);
}
}

95
framework/base/VectorIterator.php

@ -0,0 +1,95 @@
<?php
/**
* VectorIterator class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 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 <qiang.xue@gmail.com>
* @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;
}
}
Loading…
Cancel
Save