Qiang Xue
12 years ago
10 changed files with 18 additions and 1278 deletions
@ -1,209 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\framework\base; |
||||
|
||||
use yii\base\Dictionary; |
||||
|
||||
class MapItem |
||||
{ |
||||
public $data='data'; |
||||
} |
||||
|
||||
class DictionaryTest extends \yiiunit\TestCase |
||||
{ |
||||
/** |
||||
* @var \yii\base\Dictionary |
||||
*/ |
||||
protected $dictionary; |
||||
protected $item1; |
||||
protected $item2; |
||||
protected $item3; |
||||
|
||||
protected function setUp() |
||||
{ |
||||
parent::setUp(); |
||||
$this->dictionary = new Dictionary; |
||||
$this->item1 = new MapItem; |
||||
$this->item2 = new MapItem; |
||||
$this->item3 = new MapItem; |
||||
$this->dictionary->add('key1', $this->item1); |
||||
$this->dictionary->add('key2', $this->item2); |
||||
} |
||||
|
||||
protected function tearDown() |
||||
{ |
||||
parent::tearDown(); |
||||
$this->dictionary = null; |
||||
$this->item1 = null; |
||||
$this->item2 = null; |
||||
$this->item3 = null; |
||||
} |
||||
|
||||
public function testConstruct() |
||||
{ |
||||
$a = array(1, 2, 'key3' => 3); |
||||
$dictionary = new Dictionary($a); |
||||
$this->assertEquals(3, $dictionary->getCount()); |
||||
$dictionary2=new Dictionary($this->dictionary); |
||||
$this->assertEquals(2, $dictionary2->getCount()); |
||||
} |
||||
|
||||
public function testGetCount() |
||||
{ |
||||
$this->assertEquals(2, $this->dictionary->getCount()); |
||||
} |
||||
|
||||
public function testGetKeys() |
||||
{ |
||||
$keys = $this->dictionary->getKeys(); |
||||
$this->assertEquals(2, count($keys)); |
||||
$this->assertEquals('key1', $keys[0]); |
||||
$this->assertEquals('key2', $keys[1]); |
||||
} |
||||
|
||||
public function testAdd() |
||||
{ |
||||
$this->dictionary->add('key3', $this->item3); |
||||
$this->assertEquals(3, $this->dictionary->getCount()); |
||||
$this->assertTrue($this->dictionary->has('key3')); |
||||
|
||||
$this->dictionary[] = 'test'; |
||||
} |
||||
|
||||
public function testRemove() |
||||
{ |
||||
$this->dictionary->remove('key1'); |
||||
$this->assertEquals(1, $this->dictionary->getCount()); |
||||
$this->assertTrue(!$this->dictionary->has('key1')); |
||||
$this->assertTrue($this->dictionary->remove('unknown key') === null); |
||||
} |
||||
|
||||
public function testRemoveAll() |
||||
{ |
||||
$this->dictionary->add('key3', $this->item3); |
||||
$this->dictionary->removeAll(); |
||||
$this->assertEquals(0, $this->dictionary->getCount()); |
||||
$this->assertTrue(!$this->dictionary->has('key1') && !$this->dictionary->has('key2')); |
||||
|
||||
$this->dictionary->add('key3', $this->item3); |
||||
$this->dictionary->removeAll(true); |
||||
$this->assertEquals(0, $this->dictionary->getCount()); |
||||
$this->assertTrue(!$this->dictionary->has('key1') && !$this->dictionary->has('key2')); |
||||
} |
||||
|
||||
public function testHas() |
||||
{ |
||||
$this->assertTrue($this->dictionary->has('key1')); |
||||
$this->assertTrue($this->dictionary->has('key2')); |
||||
$this->assertFalse($this->dictionary->has('key3')); |
||||
} |
||||
|
||||
public function testFromArray() |
||||
{ |
||||
$array = array('key3' => $this->item3, 'key4' => $this->item1); |
||||
$this->dictionary->copyFrom($array); |
||||
|
||||
$this->assertEquals(2, $this->dictionary->getCount()); |
||||
$this->assertEquals($this->item3, $this->dictionary['key3']); |
||||
$this->assertEquals($this->item1, $this->dictionary['key4']); |
||||
|
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->dictionary->copyFrom($this); |
||||
} |
||||
|
||||
public function testMergeWith() |
||||
{ |
||||
$a = array('a' => 'v1', 'v2', array('2'), 'c' => array('3', 'c' => 'a')); |
||||
$b = array('v22', 'a' => 'v11', array('2'), 'c' => array('c' => '3', 'a')); |
||||
$c = array('a' => 'v11', 'v2', array('2'), 'c' => array('3', 'c' => '3', 'a'), 'v22', array('2')); |
||||
$dictionary = new Dictionary($a); |
||||
$dictionary2 = new Dictionary($b); |
||||
$dictionary->mergeWith($dictionary2); |
||||
$this->assertTrue($dictionary->toArray() === $c); |
||||
|
||||
$array = array('key2' => $this->item1, 'key3' => $this->item3); |
||||
$this->dictionary->mergeWith($array, false); |
||||
$this->assertEquals(3, $this->dictionary->getCount()); |
||||
$this->assertEquals($this->item1, $this->dictionary['key2']); |
||||
$this->assertEquals($this->item3, $this->dictionary['key3']); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->dictionary->mergeWith($this, false); |
||||
} |
||||
|
||||
public function testRecursiveMergeWithTraversable(){ |
||||
$dictionary = new Dictionary(); |
||||
$obj = new \ArrayObject(array( |
||||
'k1' => $this->item1, |
||||
'k2' => $this->item2, |
||||
'k3' => new \ArrayObject(array( |
||||
'k4' => $this->item3, |
||||
)) |
||||
)); |
||||
$dictionary->mergeWith($obj, true); |
||||
|
||||
$this->assertEquals(3, $dictionary->getCount()); |
||||
$this->assertEquals($this->item1, $dictionary['k1']); |
||||
$this->assertEquals($this->item2, $dictionary['k2']); |
||||
$this->assertEquals($this->item3, $dictionary['k3']['k4']); |
||||
} |
||||
|
||||
public function testArrayRead() |
||||
{ |
||||
$this->assertEquals($this->item1, $this->dictionary['key1']); |
||||
$this->assertEquals($this->item2, $this->dictionary['key2']); |
||||
$this->assertEquals(null, $this->dictionary['key3']); |
||||
} |
||||
|
||||
public function testArrayWrite() |
||||
{ |
||||
$this->dictionary['key3'] = $this->item3; |
||||
$this->assertEquals(3, $this->dictionary->getCount()); |
||||
$this->assertEquals($this->item3, $this->dictionary['key3']); |
||||
|
||||
$this->dictionary['key1'] = $this->item3; |
||||
$this->assertEquals(3, $this->dictionary->getCount()); |
||||
$this->assertEquals($this->item3, $this->dictionary['key1']); |
||||
|
||||
unset($this->dictionary['key2']); |
||||
$this->assertEquals(2, $this->dictionary->getCount()); |
||||
$this->assertTrue(!$this->dictionary->has('key2')); |
||||
|
||||
unset($this->dictionary['unknown key']); |
||||
} |
||||
|
||||
public function testArrayForeach() |
||||
{ |
||||
$n = 0; |
||||
$found = 0; |
||||
foreach ($this->dictionary as $index => $item) { |
||||
$n++; |
||||
if ($index === 'key1' && $item === $this->item1) { |
||||
$found++; |
||||
} |
||||
if ($index === 'key2' && $item === $this->item2) { |
||||
$found++; |
||||
} |
||||
} |
||||
$this->assertTrue($n == 2 && $found == 2); |
||||
} |
||||
|
||||
public function testArrayMisc() |
||||
{ |
||||
$this->assertEquals($this->dictionary->Count, count($this->dictionary)); |
||||
$this->assertTrue(isset($this->dictionary['key1'])); |
||||
$this->assertFalse(isset($this->dictionary['unknown key'])); |
||||
} |
||||
|
||||
public function testToArray() |
||||
{ |
||||
$dictionary = new Dictionary(array('key' => 'value')); |
||||
$this->assertEquals(array('key' => 'value'), $dictionary->toArray()); |
||||
} |
||||
|
||||
public function testIteratorCurrent() |
||||
{ |
||||
$dictionary = new Dictionary(array('key1' => 'value1', 'key2' => 'value2')); |
||||
$val = $dictionary->getIterator()->current(); |
||||
$this->assertEquals('value1', $val); |
||||
} |
||||
} |
@ -1,230 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace yiiunit\framework\base; |
||||
|
||||
use yii\base\Vector; |
||||
|
||||
class ListItem |
||||
{ |
||||
public $data='data'; |
||||
} |
||||
|
||||
class VectorTest extends \yiiunit\TestCase |
||||
{ |
||||
/** |
||||
* @var Vector |
||||
*/ |
||||
protected $vector; |
||||
protected $item1; |
||||
protected $item2; |
||||
protected $item3; |
||||
|
||||
protected function setUp() |
||||
{ |
||||
parent::setUp(); |
||||
$this->vector = new Vector; |
||||
$this->item1 = new ListItem; |
||||
$this->item2 = new ListItem; |
||||
$this->item3 = new ListItem; |
||||
$this->vector->add($this->item1); |
||||
$this->vector->add($this->item2); |
||||
} |
||||
|
||||
protected function tearDown() |
||||
{ |
||||
parent::tearDown(); |
||||
$this->vector = null; |
||||
$this->item1 = null; |
||||
$this->item2 = null; |
||||
$this->item3 = null; |
||||
} |
||||
|
||||
public function testConstruct() |
||||
{ |
||||
$a = array(1, 2, 3); |
||||
$vector = new Vector($a); |
||||
$this->assertEquals(3, $vector->getCount()); |
||||
$vector2 = new Vector($this->vector); |
||||
$this->assertEquals(2, $vector2->getCount()); |
||||
} |
||||
|
||||
public function testItemAt() |
||||
{ |
||||
$a = array(1, 2, null, 4); |
||||
$vector = new Vector($a); |
||||
$this->assertEquals(1, $vector->itemAt(0)); |
||||
$this->assertEquals(2, $vector->itemAt(1)); |
||||
$this->assertNull($vector->itemAt(2)); |
||||
$this->assertEquals(4, $vector->itemAt(3)); |
||||
} |
||||
|
||||
public function testGetCount() |
||||
{ |
||||
$this->assertEquals(2, $this->vector->getCount()); |
||||
$this->assertEquals(2, $this->vector->Count); |
||||
} |
||||
|
||||
public function testAdd() |
||||
{ |
||||
$this->vector->add(null); |
||||
$this->vector->add($this->item3); |
||||
$this->assertEquals(4, $this->vector->getCount()); |
||||
$this->assertEquals(3, $this->vector->indexOf($this->item3)); |
||||
} |
||||
|
||||
public function testInsertAt() |
||||
{ |
||||
$this->vector->insertAt(0, $this->item3); |
||||
$this->assertEquals(3, $this->vector->getCount()); |
||||
$this->assertEquals(2, $this->vector->indexOf($this->item2)); |
||||
$this->assertEquals(0, $this->vector->indexOf($this->item3)); |
||||
$this->assertEquals(1, $this->vector->indexOf($this->item1)); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->vector->insertAt(4, $this->item3); |
||||
} |
||||
|
||||
public function testRemove() |
||||
{ |
||||
$this->vector->remove($this->item1); |
||||
$this->assertEquals(1, $this->vector->getCount()); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item1)); |
||||
$this->assertEquals(0, $this->vector->indexOf($this->item2)); |
||||
|
||||
$this->assertEquals(false, $this->vector->remove($this->item1)); |
||||
|
||||
} |
||||
|
||||
public function testRemoveAt() |
||||
{ |
||||
$this->vector->add($this->item3); |
||||
$this->vector->removeAt(1); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item2)); |
||||
$this->assertEquals(1, $this->vector->indexOf($this->item3)); |
||||
$this->assertEquals(0, $this->vector->indexOf($this->item1)); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->vector->removeAt(2); |
||||
} |
||||
|
||||
public function testRemoveAll() |
||||
{ |
||||
$this->vector->add($this->item3); |
||||
$this->vector->removeAll(); |
||||
$this->assertEquals(0, $this->vector->getCount()); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item1)); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item2)); |
||||
|
||||
$this->vector->add($this->item3); |
||||
$this->vector->removeAll(true); |
||||
$this->assertEquals(0, $this->vector->getCount()); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item1)); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item2)); |
||||
} |
||||
|
||||
public function testHas() |
||||
{ |
||||
$this->assertTrue($this->vector->has($this->item1)); |
||||
$this->assertTrue($this->vector->has($this->item2)); |
||||
$this->assertFalse($this->vector->has($this->item3)); |
||||
} |
||||
|
||||
public function testIndexOf() |
||||
{ |
||||
$this->assertEquals(0, $this->vector->indexOf($this->item1)); |
||||
$this->assertEquals(1, $this->vector->indexOf($this->item2)); |
||||
$this->assertEquals(-1, $this->vector->indexOf($this->item3)); |
||||
} |
||||
|
||||
public function testFromArray() |
||||
{ |
||||
$array = array($this->item3, $this->item1); |
||||
$this->vector->copyFrom($array); |
||||
$this->assertTrue(count($array) == 2 && $this->vector[0] === $this->item3 && $this->vector[1] === $this->item1); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->vector->copyFrom($this); |
||||
} |
||||
|
||||
public function testMergeWith() |
||||
{ |
||||
$array = array($this->item3, $this->item1); |
||||
$this->vector->mergeWith($array); |
||||
$this->assertTrue($this->vector->getCount() == 4 && $this->vector[0] === $this->item1 && |
||||
$this->vector[3] === $this->item1); |
||||
|
||||
$a = array(1); |
||||
$vector = new Vector($a); |
||||
$this->vector->mergeWith($vector); |
||||
$this->assertTrue($this->vector->getCount() == 5 && $this->vector[0] === $this->item1 && |
||||
$this->vector[3] === $this->item1 && $this->vector[4] === 1); |
||||
|
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$this->vector->mergeWith($this); |
||||
} |
||||
|
||||
public function testToArray() |
||||
{ |
||||
$array = $this->vector->toArray(); |
||||
$this->assertTrue(count($array) == 2 && $array[0] === $this->item1 && $array[1] === $this->item2); |
||||
} |
||||
|
||||
public function testArrayRead() |
||||
{ |
||||
$this->assertTrue($this->vector[0] === $this->item1); |
||||
$this->assertTrue($this->vector[1] === $this->item2); |
||||
$this->setExpectedException('yii\base\InvalidParamException'); |
||||
$a = $this->vector[2]; |
||||
} |
||||
|
||||
public function testGetIterator() |
||||
{ |
||||
$n = 0; |
||||
$found = 0; |
||||
foreach ($this->vector as $index => $item) { |
||||
foreach ($this->vector as $a => $b) { |
||||
// test of iterator |
||||
} |
||||
$n++; |
||||
if ($index === 0 && $item === $this->item1) { |
||||
$found++; |
||||
} |
||||
if ($index === 1 && $item === $this->item2) { |
||||
$found++; |
||||
} |
||||
} |
||||
$this->assertTrue($n == 2 && $found == 2); |
||||
} |
||||
|
||||
public function testArrayMisc() |
||||
{ |
||||
$this->assertEquals($this->vector->Count, count($this->vector)); |
||||
$this->assertTrue(isset($this->vector[1])); |
||||
$this->assertFalse(isset($this->vector[2])); |
||||
} |
||||
|
||||
public function testOffsetSetAdd() |
||||
{ |
||||
$vector = new Vector(array(1, 2, 3)); |
||||
$vector->offsetSet(null, 4); |
||||
$this->assertEquals(array(1, 2, 3, 4), $vector->toArray()); |
||||
} |
||||
|
||||
public function testOffsetSetReplace() |
||||
{ |
||||
$vector = new Vector(array(1, 2, 3)); |
||||
$vector->offsetSet(1, 4); |
||||
$this->assertEquals(array(1, 4, 3), $vector->toArray()); |
||||
} |
||||
|
||||
public function testOffsetUnset() |
||||
{ |
||||
$vector = new Vector(array(1, 2, 3)); |
||||
$vector->offsetUnset(1); |
||||
$this->assertEquals(array(1, 3), $vector->toArray()); |
||||
} |
||||
|
||||
public function testIteratorCurrent() |
||||
{ |
||||
$vector = new Vector(array('value1', 'value2')); |
||||
$val = $vector->getIterator()->current(); |
||||
$this->assertEquals('value1', $val); |
||||
} |
||||
} |
@ -1,297 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
use yii\helpers\ArrayHelper; |
||||
|
||||
/** |
||||
* Dictionary implements a collection that stores key-value pairs. |
||||
* |
||||
* You can access, add or remove an item with a key by using |
||||
* [[itemAt()]], [[add()]], and [[remove()]]. |
||||
* |
||||
* To get the number of the items in the dictionary, use [[getCount()]]. |
||||
* |
||||
* Because Dictionary implements a set of SPL interfaces, it can be used |
||||
* like a regular PHP array as follows, |
||||
* |
||||
* ~~~ |
||||
* $dictionary[$key] = $value; // add a key-value pair |
||||
* unset($dictionary[$key]); // remove the value with the specified key |
||||
* if (isset($dictionary[$key])) // if the dictionary contains the key |
||||
* foreach ($dictionary as $key => $value) // traverse the items in the dictionary |
||||
* $n = count($dictionary); // returns the number of items in the dictionary |
||||
* ~~~ |
||||
* |
||||
* @property integer $count the number of items in the dictionary |
||||
* @property array $keys The keys in the dictionary |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Countable |
||||
{ |
||||
/** |
||||
* @var array internal data storage |
||||
*/ |
||||
private $_d = array(); |
||||
|
||||
/** |
||||
* Constructor. |
||||
* Initializes the dictionary with an array or an iterable object. |
||||
* @param mixed $data the initial data to be populated into the dictionary. |
||||
* This can be an array or an iterable object. |
||||
* @param array $config name-value pairs that will be used to initialize the object properties |
||||
* @throws Exception if data is not well formed (neither an array nor an iterable object) |
||||
*/ |
||||
public function __construct($data = array(), $config = array()) |
||||
{ |
||||
if (!empty($data)) { |
||||
$this->copyFrom($data); |
||||
} |
||||
parent::__construct($config); |
||||
} |
||||
|
||||
/** |
||||
* Returns an iterator for traversing the items in the dictionary. |
||||
* This method is required by the SPL interface `IteratorAggregate`. |
||||
* It will be implicitly called when you use `foreach` to traverse the dictionary. |
||||
* @return DictionaryIterator an iterator for traversing the items in the dictionary. |
||||
*/ |
||||
public function getIterator() |
||||
{ |
||||
return new DictionaryIterator($this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of items in the dictionary. |
||||
* This method is required by the SPL `Countable` interface. |
||||
* It will be implicitly called when you use `count($dictionary)`. |
||||
* @return integer number of items in the dictionary. |
||||
*/ |
||||
public function count() |
||||
{ |
||||
return $this->getCount(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of items in the dictionary. |
||||
* @return integer the number of items in the dictionary |
||||
*/ |
||||
public function getCount() |
||||
{ |
||||
return count($this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Returns the keys stored in the dictionary. |
||||
* @return array the key list |
||||
*/ |
||||
public function getKeys() |
||||
{ |
||||
return array_keys($this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Returns the item with the specified key. |
||||
* @param mixed $key the key |
||||
* @return mixed the element with the specified key. |
||||
* Null if the key cannot be found in the dictionary. |
||||
*/ |
||||
public function itemAt($key) |
||||
{ |
||||
return isset($this->_d[$key]) ? $this->_d[$key] : null; |
||||
} |
||||
|
||||
/** |
||||
* Adds an item into the dictionary. |
||||
* Note, if the specified key already exists, the old value will be overwritten. |
||||
* @param mixed $key key |
||||
* @param mixed $value value |
||||
* @throws Exception if the dictionary is read-only |
||||
*/ |
||||
public function add($key, $value) |
||||
{ |
||||
if ($key === null) { |
||||
$this->_d[] = $value; |
||||
} else { |
||||
$this->_d[$key] = $value; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Removes an item from the dictionary by its key. |
||||
* @param mixed $key the key of the item to be removed |
||||
* @return mixed the removed value, null if no such key exists. |
||||
* @throws Exception if the dictionary is read-only |
||||
*/ |
||||
public function remove($key) |
||||
{ |
||||
if (isset($this->_d[$key])) { |
||||
$value = $this->_d[$key]; |
||||
unset($this->_d[$key]); |
||||
return $value; |
||||
} else { // the value is null |
||||
unset($this->_d[$key]); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Removes all items from the dictionary. |
||||
* @param boolean $safeClear whether to clear every item by calling [[remove]]. |
||||
* Defaults to false, meaning all items in the dictionary will be cleared directly |
||||
* without calling [[remove]]. |
||||
*/ |
||||
public function removeAll($safeClear = false) |
||||
{ |
||||
if ($safeClear) { |
||||
foreach (array_keys($this->_d) as $key) { |
||||
$this->remove($key); |
||||
} |
||||
} else { |
||||
$this->_d = array(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a value indicating whether the dictionary contains the specified key. |
||||
* @param mixed $key the key |
||||
* @return boolean whether the dictionary contains an item with the specified key |
||||
*/ |
||||
public function has($key) |
||||
{ |
||||
return isset($this->_d[$key]) || array_key_exists($key, $this->_d); |
||||
} |
||||
|
||||
/** |
||||
* Returns the dictionary as a PHP array. |
||||
* @return array the list of items in array |
||||
*/ |
||||
public function toArray() |
||||
{ |
||||
return $this->_d; |
||||
} |
||||
|
||||
/** |
||||
* Copies iterable data into the dictionary. |
||||
* Note, existing data in the dictionary will be cleared first. |
||||
* @param mixed $data the data to be copied from, must be an array or an object implementing `Traversable` |
||||
* @throws InvalidParamException if data is neither an array nor an iterator. |
||||
*/ |
||||
public function copyFrom($data) |
||||
{ |
||||
if (is_array($data) || $data instanceof \Traversable) { |
||||
if (!empty($this->_d)) { |
||||
$this->removeAll(); |
||||
} |
||||
if ($data instanceof self) { |
||||
$data = $data->_d; |
||||
} |
||||
foreach ($data as $key => $value) { |
||||
$this->add($key, $value); |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('Data must be either an array or an object implementing Traversable.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Merges iterable data into the dictionary. |
||||
* |
||||
* Existing elements in the dictionary will be overwritten if their keys are the same as those in the source. |
||||
* If the merge is recursive, the following algorithm is performed: |
||||
* |
||||
* - the dictionary data is saved as $a, and the source data is saved as $b; |
||||
* - if $a and $b both have an array indexed at the same string key, the arrays will be merged using this algorithm; |
||||
* - any integer-indexed elements in $b will be appended to $a; |
||||
* - any string-indexed elements in $b will overwrite elements in $a with the same index; |
||||
* |
||||
* @param array|\Traversable $data the data to be merged with. It must be an array or object implementing Traversable |
||||
* @param boolean $recursive whether the merging should be recursive. |
||||
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`. |
||||
*/ |
||||
public function mergeWith($data, $recursive = true) |
||||
{ |
||||
if (is_array($data) || $data instanceof \Traversable) { |
||||
if ($data instanceof self) { |
||||
$data = $data->_d; |
||||
} |
||||
if ($recursive) { |
||||
if ($data instanceof \Traversable) { |
||||
$d = array(); |
||||
foreach ($data as $key => $value) { |
||||
$d[$key] = $value; |
||||
} |
||||
$this->_d = ArrayHelper::merge($this->_d, $d); |
||||
} else { |
||||
$this->_d = ArrayHelper::merge($this->_d, $data); |
||||
} |
||||
} else { |
||||
foreach ($data as $key => $value) { |
||||
$this->add($key, $value); |
||||
} |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('The data to be merged with must be an array or an object implementing Traversable.'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns whether there is an element at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `isset($dictionary[$offset])`. |
||||
* This is equivalent to [[contains]]. |
||||
* @param mixed $offset the offset to check on |
||||
* @return boolean |
||||
*/ |
||||
public function offsetExists($offset) |
||||
{ |
||||
return $this->has($offset); |
||||
} |
||||
|
||||
/** |
||||
* Returns the element at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `$value = $dictionary[$offset];`. |
||||
* This is equivalent to [[itemAt]]. |
||||
* @param mixed $offset the offset to retrieve element. |
||||
* @return mixed the element at the offset, null if no element is found at the offset |
||||
*/ |
||||
public function offsetGet($offset) |
||||
{ |
||||
return $this->itemAt($offset); |
||||
} |
||||
|
||||
/** |
||||
* Sets the element at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `$dictionary[$offset] = $item;`. |
||||
* If the offset is null, the new item will be appended to the dictionary. |
||||
* Otherwise, the existing item at the offset will be replaced with the new item. |
||||
* This is equivalent to [[add]]. |
||||
* @param mixed $offset the offset to set element |
||||
* @param mixed $item the element value |
||||
*/ |
||||
public function offsetSet($offset, $item) |
||||
{ |
||||
$this->add($offset, $item); |
||||
} |
||||
|
||||
/** |
||||
* Unsets the element at the specified offset. |
||||
* This method is required by the SPL interface `ArrayAccess`. |
||||
* It is implicitly called when you use something like `unset($dictionary[$offset])`. |
||||
* This is equivalent to [[remove]]. |
||||
* @param mixed $offset the offset to unset element |
||||
*/ |
||||
public function offsetUnset($offset) |
||||
{ |
||||
$this->remove($offset); |
||||
} |
||||
} |
@ -1,92 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* DictionaryIterator implements the SPL `Iterator` interface for [[Dictionary]]. |
||||
* |
||||
* It allows [[Dictionary]] 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 DictionaryIterator implements \Iterator |
||||
{ |
||||
/** |
||||
* @var array the data to be iterated through |
||||
*/ |
||||
private $_d; |
||||
/** |
||||
* @var array list of keys in the map |
||||
*/ |
||||
private $_keys; |
||||
/** |
||||
* @var mixed current key |
||||
*/ |
||||
private $_key; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param array $data the data to be iterated through |
||||
*/ |
||||
public function __construct(&$data) |
||||
{ |
||||
$this->_d = &$data; |
||||
$this->_keys = array_keys($data); |
||||
$this->_key = reset($this->_keys); |
||||
} |
||||
|
||||
/** |
||||
* Rewinds the index of the current item. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
*/ |
||||
public function rewind() |
||||
{ |
||||
$this->_key = reset($this->_keys); |
||||
} |
||||
|
||||
/** |
||||
* Returns the key of the current array element. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
* @return mixed the key of the current array element |
||||
*/ |
||||
public function key() |
||||
{ |
||||
return $this->_key; |
||||
} |
||||
|
||||
/** |
||||
* Returns the current array element. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
* @return mixed the current array element |
||||
*/ |
||||
public function current() |
||||
{ |
||||
return $this->_d[$this->_key]; |
||||
} |
||||
|
||||
/** |
||||
* Moves the internal pointer to the next element. |
||||
* This method is required by the SPL interface `Iterator`. |
||||
*/ |
||||
public function next() |
||||
{ |
||||
$this->_key = next($this->_keys); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether there is an element 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->_key !== false; |
||||
} |
||||
} |
@ -1,341 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 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, |
||||
* |
||||
* ~~~ |
||||
* $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()]]. |
||||
* |
||||
* @property integer $count the number of items in the vector |
||||
* |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @since 2.0 |
||||
*/ |
||||
class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Countable |
||||
{ |
||||
/** |
||||
* @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. |
||||
* @param array $config name-value pairs that will be used to initialize the object properties |
||||
* @throws Exception if data is not well formed (neither an array nor an iterable object) |
||||
*/ |
||||
public function __construct($data = array(), $config = array()) |
||||
{ |
||||
if (!empty($data)) { |
||||
$this->copyFrom($data); |
||||
} |
||||
parent::__construct($config); |
||||
} |
||||
|
||||
/** |
||||
* 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 VectorIterator 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 InvalidParamException 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]; |
||||
} else { |
||||
throw new InvalidParamException('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 InvalidParamException if the index specified is out of range, or the vector is read-only. |
||||
*/ |
||||
public function insertAt($index, $item) |
||||
{ |
||||
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++; |
||||
} else { |
||||
throw new InvalidParamException('Index out of range: ' . $index); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 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 InvalidParamException if the index is out of range, or the vector is read only. |
||||
*/ |
||||
public function removeAt($index) |
||||
{ |
||||
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; |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('Index out of range: ' . $index); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Removes all items from the vector. |
||||
* @param boolean $safeClear whether to clear every item by calling [[removeAt]]. |
||||
* Defaults to false, meaning all items in the vector will be cleared directly |
||||
* without calling [[removeAt]]. |
||||
*/ |
||||
public function removeAll($safeClear = false) |
||||
{ |
||||
if ($safeClear) { |
||||
for ($i = $this->_c - 1; $i >= 0; --$i) { |
||||
$this->removeAt($i); |
||||
} |
||||
} else { |
||||
$this->_d = array(); |
||||
$this->_c = 0; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 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 has($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 InvalidParamException 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->removeAll(); |
||||
} |
||||
if ($data instanceof self) { |
||||
$data = $data->_d; |
||||
} |
||||
foreach ($data as $item) { |
||||
$this->add($item); |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('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 array|\Traversable $data the data to be merged with. It must be an array or object implementing Traversable |
||||
* @throws InvalidParamException 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); |
||||
} |
||||
} else { |
||||
throw new InvalidParamException('The data to be merged with must be 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[$offset])`. |
||||
* @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[$offset];`. |
||||
* This is equivalent to [[itemAt]]. |
||||
* @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[$offset] = $item;`. |
||||
* 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[$offset])`. |
||||
* 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); |
||||
} |
||||
} |
@ -1,92 +0,0 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 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…
Reference in new issue