Browse Source

finished Vector.

tags/2.0.0-beta
Qiang Xue 14 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 class Component
{ {
private $_e; private $_e;
private $_m; private $_b;
/** /**
* Returns a property value, an event handler list or a behavior based on its name. * 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) public function __get($name)
{ {
$getter = 'get' . $name; $getter = 'get' . $name;
if(method_exists($this, $getter)) if (method_exists($this, $getter)) { // read property, e.g. getName()
return $this->$getter(); return $this->$getter();
else if(method_exists($this, $name) && strncasecmp($name, 'on', 2)===0) }
{ elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event, e.g. onClick()
$name=strtolower($name); $name = strtolower($name);
if(!isset($this->_e[$name])) if (!isset($this->_e[$name])) {
$this->_e[$name]=new yii\collections\Vector; $this->_e[$name] = new \yii\collections\Vector;
}
return $this->_e[$name]; return $this->_e[$name];
} }
else if(isset($this->_m[$name])) elseif (isset($this->_b[$name])) { // behavior
return $this->_m[$name]; return $this->_b[$name];
else if(is_array($this->_m)) // has attached behaviors }
{ elseif (is_array($this->_b)) { // a behavior property
foreach($this->_m as $object) foreach ($this->_b as $object) {
{ if ($object->getEnabled() && $object->canGetProperty($name)) {
if($object->getEnabled() && $object->canGetProperty($name))
return $object->$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. * @throws CException if the property/event is not defined or the property is read only.
* @see __get * @see __get
*/ */
public function __set($name,$value) public function __set($name, $value)
{ {
$setter='set'.$name; $setter = 'set' . $name;
if(method_exists($this,$setter)) if (method_exists($this, $setter)) {
return $this->$setter($value); return $this->$setter($value);
else if(method_exists($this,$name) && strncasecmp($name,'on',2)===0) }
{ elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) {
$name=strtolower($name); $name = strtolower($name);
if(!isset($this->_e[$name])) if (!isset($this->_e[$name])) {
$this->_e[$name]=new yii\collections\Vector; $this->_e[$name] = new \yii\collections\Vector;
}
return $this->_e[$name]->add($value); return $this->_e[$name]->add($value);
} }
else if(is_array($this->_m)) elseif (is_array($this->_b)) {
{ foreach ($this->_b as $object) {
foreach($this->_m as $object) if ($object->getEnabled() && $object->canSetProperty($name)) {
{ return $object->$name = $value;
if($object->getEnabled() && $object->canSetProperty($name)) }
return $object->$name=$value;
} }
} }
if(method_exists($this,'get'.$name)) if (method_exists($this, 'get' . $name)) {
throw new Exception('Unable to set read-only property: ' . get_class($this) . '.' $name); throw new Exception('Setting read-only property: ' . get_class($this) . '.' $name);
else }
throw new Exception('Undefined 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) public function __isset($name)
{ {
$getter='get'.$name; $getter = 'get' . $name;
if(method_exists($this,$getter)) if (method_exists($this, $getter)) { // property is not null
return $this->$getter()!==null; return $this->$getter() !== null;
else if(method_exists($this,$name) && strncasecmp($name,'on',2)===0) }
{ elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // has event handler
$name=strtolower($name); $name = strtolower($name);
return isset($this->_e[$name]) && $this->_e[$name]->getCount(); return isset($this->_e[$name]) && $this->_e[$name]->getCount();
} }
else if(isset($this->_m[$name])) elseif (isset($this->_b[$name])) { // has behavior
return true; return true;
else if(is_array($this->_m)) }
{ elseif (is_array($this->_b)) {
foreach($this->_m as $object) foreach ($this->_b as $object) {
{ if ($object->getEnabled() && $object->canGetProperty($name)) {
if($object->getEnabled() && $object->canGetProperty($name)) return $object->$name !== null;
return true; }
} }
} }
return false; return false;
@ -124,23 +127,26 @@ class Component
*/ */
public function __unset($name) public function __unset($name)
{ {
$setter='set'.$name; $setter = 'set' . $name;
if(method_exists($this,$setter)) if (method_exists($this, $setter)) {
$this->$setter(null); $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)]); unset($this->_e[strtolower($name)]);
else if(isset($this->_m[$name])) }
elseif (isset($this->_b[$name])) {
$this->detachBehavior($name); $this->detachBehavior($name);
else if(is_array($this->_m)) }
{ elseif (is_array($this->_b)) {
foreach($this->_m as $object) foreach ($this->_b as $object)
{ {
if($object->getEnabled() && $object->canSetProperty($name)) if ($object->getEnabled() && $object->canSetProperty($name)) {
return $object->$name=null; return $object->$name = null;
}
} }
} }
else if(method_exists($this,'get'.$name)) elseif (method_exists($this, 'get' . $name))
throw new Exception('Unable to unset read-only property: ' . get_class($this) . '.' $name); throw new Exception('Unsetting read-only property: ' . get_class($this) . '.' $name);
} }
/** /**
@ -152,18 +158,23 @@ class Component
* @return mixed the method return value * @return mixed the method return value
* @since 1.0.2 * @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)) if ($object->getEnabled() && method_exists($object, $name)) {
return call_user_func_array(array($object,$name),$parameters); 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 . '()'); throw new Exception('Unknown method: ' . get_class($this) . '::' $name . '()');
} }
@ -176,7 +187,7 @@ class Component
*/ */
public function asa($behavior) 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) public function attachBehaviors($behaviors)
{ {
foreach($behaviors as $name=>$behavior) foreach ($behaviors as $name => $behavior)
$this->attachBehavior($name,$behavior); $this->attachBehavior($name, $behavior);
} }
/** /**
@ -206,11 +217,11 @@ class Component
*/ */
public function detachBehaviors() 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->detachBehavior($name);
$this->_m=null; $this->_b = null;
} }
} }
@ -225,13 +236,13 @@ class Component
* @return IBehavior the behavior object * @return IBehavior the behavior object
* @since 1.0.2 * @since 1.0.2
*/ */
public function attachBehavior($name,$behavior) public function attachBehavior($name, $behavior)
{ {
if(!($behavior instanceof IBehavior)) if (!($behavior instanceof IBehavior))
$behavior=Yii::createComponent($behavior); $behavior = Yii::createComponent($behavior);
$behavior->setEnabled(true); $behavior->setEnabled(true);
$behavior->attach($this); $behavior->attach($this);
return $this->_m[$name]=$behavior; return $this->_b[$name] = $behavior;
} }
/** /**
@ -243,11 +254,11 @@ class Component
*/ */
public function detachBehavior($name) public function detachBehavior($name)
{ {
if(isset($this->_m[$name])) if (isset($this->_b[$name]))
{ {
$this->_m[$name]->detach($this); $this->_b[$name]->detach($this);
$behavior=$this->_m[$name]; $behavior = $this->_b[$name];
unset($this->_m[$name]); unset($this->_b[$name]);
return $behavior; return $behavior;
} }
} }
@ -258,9 +269,9 @@ class Component
*/ */
public function enableBehaviors() public function enableBehaviors()
{ {
if($this->_m!==null) if ($this->_b !== null)
{ {
foreach($this->_m as $behavior) foreach ($this->_b as $behavior)
$behavior->setEnabled(true); $behavior->setEnabled(true);
} }
} }
@ -271,9 +282,9 @@ class Component
*/ */
public function disableBehaviors() public function disableBehaviors()
{ {
if($this->_m!==null) if ($this->_b !== null)
{ {
foreach($this->_m as $behavior) foreach ($this->_b as $behavior)
$behavior->setEnabled(false); $behavior->setEnabled(false);
} }
} }
@ -287,8 +298,8 @@ class Component
*/ */
public function enableBehavior($name) public function enableBehavior($name)
{ {
if(isset($this->_m[$name])) if (isset($this->_b[$name]))
$this->_m[$name]->setEnabled(true); $this->_b[$name]->setEnabled(true);
} }
/** /**
@ -299,8 +310,8 @@ class Component
*/ */
public function disableBehavior($name) public function disableBehavior($name)
{ {
if(isset($this->_m[$name])) if (isset($this->_b[$name]))
$this->_m[$name]->setEnabled(false); $this->_b[$name]->setEnabled(false);
} }
/** /**
@ -308,13 +319,14 @@ class Component
* A property is defined if there is a getter or setter method * A property is defined if there is a getter or setter method
* defined in the class. Note, property names are case-insensitive. * defined in the class. Note, property names are case-insensitive.
* @param string $name the property name * @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 * @return boolean whether the property is defined
* @see canGetProperty * @see canGetProperty
* @see canSetProperty * @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 * @return boolean whether the property can be read
* @see canSetProperty * @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 * @return boolean whether the property can be written
* @see canGetProperty * @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) 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) public function hasEventHandler($name)
{ {
$name=strtolower($name); $name = strtolower($name);
return isset($this->_e[$name]) && $this->_e[$name]->getCount()>0; return isset($this->_e[$name]) && $this->_e[$name]->getCount() > 0;
} }
/** /**
@ -376,16 +388,16 @@ class Component
*/ */
public function getEventHandlers($name) public function getEventHandlers($name)
{ {
if($this->hasEvent($name)) if ($this->hasEvent($name))
{ {
$name=strtolower($name); $name = strtolower($name);
if(!isset($this->_e[$name])) if (!isset($this->_e[$name]))
$this->_e[$name]=new CList; $this->_e[$name] = new CList;
return $this->_e[$name]; return $this->_e[$name];
} }
else else
throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.', throw new CException(Yii::t('yii', 'Event "{class}.{event}" is not defined.',
array('{class}'=>get_class($this), '{event}'=>$name))); array('{class}' => get_class($this), '{event}' => $name)));
} }
/** /**
@ -420,7 +432,7 @@ class Component
* @throws CException if the event is not defined * @throws CException if the event is not defined
* @see detachEventHandler * @see detachEventHandler
*/ */
public function attachEventHandler($name,$handler) public function attachEventHandler($name, $handler)
{ {
$this->getEventHandlers($name)->add($handler); $this->getEventHandlers($name)->add($handler);
} }
@ -433,10 +445,10 @@ class Component
* @return boolean if the detachment process is successful * @return boolean if the detachment process is successful
* @see attachEventHandler * @see attachEventHandler
*/ */
public function detachEventHandler($name,$handler) public function detachEventHandler($name, $handler)
{ {
if($this->hasEventHandler($name)) if ($this->hasEventHandler($name))
return $this->getEventHandlers($name)->remove($handler)!==false; return $this->getEventHandlers($name)->remove($handler) !== false;
else else
return false; return false;
} }
@ -449,43 +461,43 @@ class Component
* @param CEvent $event the event parameter * @param CEvent $event the event parameter
* @throws CException if the event is undefined or an event handler is invalid. * @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); $name = strtolower($name);
if(isset($this->_e[$name])) if (isset($this->_e[$name]))
{ {
foreach($this->_e[$name] as $handler) foreach ($this->_e[$name] as $handler)
{ {
if(is_string($handler)) if (is_string($handler))
call_user_func($handler,$event); call_user_func($handler, $event);
else if(is_callable($handler,true)) elseif (is_callable($handler, true))
{ {
if(is_array($handler)) if (is_array($handler))
{ {
// an array: 0 - object, 1 - method name // an array: 0 - object, 1 - method name
list($object,$method)=$handler; list($object, $method) = $handler;
if(is_string($object)) // static method call if (is_string($object)) // static method call
call_user_func($handler,$event); call_user_func($handler, $event);
else if(method_exists($object,$method)) elseif (method_exists($object, $method))
$object->$method($event); $object->$method($event);
else else
throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{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}'=>$handler[1]))); array('{class}' => get_class($this), '{event}' => $name, '{handler}' => $handler[1])));
} }
else // PHP 5.3: anonymous function else // PHP 5.3: anonymous function
call_user_func($handler,$event); call_user_func($handler, $event);
} }
else else
throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{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)))); array('{class}' => get_class($this), '{event}' => $name, '{handler}' => gettype($handler))));
// stop further handling if param.handled is set true // stop further handling if param.handled is set true
if(($event instanceof CEvent) && $event->handled) if (($event instanceof CEvent) && $event->handled)
return; return;
} }
} }
else if(YII_DEBUG && !$this->hasEvent($name)) elseif (YII_DEBUG && !$this->hasEvent($name))
throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.', throw new CException(Yii::t('yii', 'Event "{class}.{event}" is not defined.',
array('{class}'=>get_class($this), '{event}'=>$name))); array('{class}' => get_class($this), '{event}' => $name)));
} }
/** /**
@ -510,16 +522,16 @@ class Component
* @return mixed the expression result * @return mixed the expression result
* @since 1.1.0 * @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_); extract($_data_);
return eval('return '.$_expression_.';'); return eval('return ' . $_expression_ . ';');
} }
else else
{ {
$_data_[]=$this; $_data_[] = $this;
return call_user_func_array($_expression_, $_data_); return call_user_func_array($_expression_, $_data_);
} }
} }

4
framework/base/Event.php

@ -3,7 +3,7 @@
namespace yii\base; 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. * It encapsulates the parameters associated with an event.
* The {@link sender} property describes who raises the event. * The {@link sender} property describes who raises the event.
@ -16,7 +16,7 @@ namespace yii\base;
* @package system.base * @package system.base
* @since 1.0 * @since 1.0
*/ */
class CEvent extends CComponent class Event extends Component
{ {
/** /**
* @var object the sender of this event * @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