PHP Spl Iterators,PHP SPL使用


PHP文档

PHP SPL 提供一系列迭代器以遍历不同的对象,有些比较实用(如ArrayAccess),有些比较鸡肋,从来没有使用过。

Iterator

实现一个最简单的迭代器接口

<?php
class MyIterator implements Iterator
{
    private $array = [];

    private $valid = false;

    public function __construct(array $array)
    {
        $this->array = $array;
    }

    /**
     * 返回到迭代器的第一个元素
     * @author jiangyi
     */
    function rewind()
    {
        $this->valid = (false !== reset($this->array));
    }

    /**
     * 返回当前元素
     * @return mixed
     * @author jiangyi
     */
    function current()
    {
        return current($this->array);
    }

    /**
     * 返回当前元素的键
     * @return int
     * @author jiangyi
     */
    function key()
    {
        return key($this->array);
    }

    /**
     * 向前移动到下一个元素
     * @author jiangyi
     */
    function next()
    {
        $this->valid = (false !== next($this->array));
    }

    /**
     * 检查当前位置是否有效
     * @return bool
     * @author jiangyi
     */
    function valid()
    {
        return $this->valid;
    }
}

$array = [
    'a' => "firstelement",
    "secondelement",
    "lastelement",
];
$it = new MyIterator($array);

foreach ($it as $key => $value) {
    echo "{$key}=>{$value}\n";
}

$it->rewind();
while ($it->valid()) {
    echo "{$it->key()}=>{$it->current()}\n";
    $it->next();
}

Countable

实现统计接口

<?php
class MyCountable implements Countable
{
    private $myCount = 3;

    public function count()
    {
        return $this->myCount;
    }
}

$countable = new MyCountable();
var_dump($countable->count());
var_dump(count($countable));

AppendIterator

这个迭代器可以遍历很多的迭代器

用在什么地方呢?暂时没想到

<?php

$arrayIteratorOne = new ArrayIterator(['a', 'b', 'c']);
$arrayIteratorTwo = new ArrayIterator(['d', 'e', 'f']);

$iterator = new AppendIterator;
$iterator->append($arrayIteratorOne);
$iterator->append($arrayIteratorTwo);

foreach ($iterator as $current) {
    echo $current . PHP_EOL;
}

// 输出a b c d e f

ArrayAccess

提供像访问数组一样访问对象的能力的接口

大部分框架的model都实现它来达到上述的效果

<?php

class MyArrayAccess implements ArrayAccess, IteratorAggregate
{
    private $container = [];
    public $title;
    public $author;
    public $category;

    public function __construct($title, $author, $category)
    {
        $this->container = [
            "one"   => 1,
            "two"   => 2,
            "three" => 3,
        ];
        $this->title = $title;
        $this->author = $author;
        $this->category = $category;
    }

    /**
     * 设置一个偏移位置的值
     * @param mixed $offset
     * @param mixed $value
     * @author jiangyi
     */
    public function offsetSet($offset, $value)
    {
        $this->{$offset} = $value;
    }

    /**
     * 检查一个偏移位置是否存在
     * @param mixed $offset
     * @return bool
     * @author jiangyi
     */
    public function offsetExists($offset)
    {
        return isset($this->{$offset});
    }

    /**
     * 复位一个偏移位置的值
     * @param mixed $offset
     * @author jiangyi
     */
    public function offsetUnset($offset)
    {
        unset($this->{$offset});
    }

    /**
     * 获取一个偏移位置的值
     * @param mixed $offset
     * @return mixed|null
     * @author jiangyi
     */
    public function offsetGet($offset)
    {
        return isset($this->{$offset}) ? $this->{$offset} : null;
    }

    function getIterator()
    {
        return new ArrayIterator($this);
    }
}

$obj = new MyArrayAccess('a', 'wen', 'new');

var_dump(isset($obj['title']));
var_dump($obj["title"]);
unset($obj["title"]);
var_dump(isset($obj["title"]));
$obj["title"] = "A value";
var_dump($obj["title"]);
$obj['a'] = 'Append 1';
$obj['b'] = 'Append 2';
$obj['c'] = 'Append 3';

foreach ($obj as $field => $value) {
    echo "$field=>$value\n";
}

ArrayIterator

这个迭代器允许在遍历数组和对象时删除和更新值与键

其实它实现了ArrayAccess , SeekableIterator , Countable , Serializable拥有更多的功能

<?php

$array = ['a', 'b', 'c', 'd'];

try {
    $object = new ArrayIterator($array);
    foreach ($object as $key => $value) {
        echo $key . ' => ' . $value . PHP_EOL;
    }
} catch (Exception $e) {
    echo $e->getMessage();
}

ArrayObject

更像手动的foreach

<?php

$array = ['a', 'b', 'c', 'd'];

$arrayObj = new ArrayObject($array);
$arrayObj->append('e');
$arrayObj->natcasesort();
echo 'count->' . $arrayObj->count() . PHP_EOL;
$arrayObj->offsetUnset(3);
if ($arrayObj->offsetExists(2)) {
    echo 'Offset Exists' . PHP_EOL;
}
$arrayObj->offsetSet(5, 'f');
echo $arrayObj->offsetGet(4) . PHP_EOL;
for ($iterator = $arrayObj->getIterator();
     $iterator->valid();
     $iterator->next()) {
    echo $iterator->key() . ' => ' . $iterator->current() . PHP_EOL;
}

CachingIterator

没用过。。。

<?php

$array = ['a', 'b', 'c', 'd'];

try {
    $object = new CachingIterator(new ArrayIterator($array));
    foreach ($object as $value) {
        echo $value . PHP_EOL;
    }
} catch (Exception $e) {
    echo $e->getMessage();
}

DirectoryIterator

用来遍历目录,获取文件的信息很方便

<?php

try {
    foreach (new DirectoryIterator(__DIR__) as $item) {
        if ($item->getFilename() == 'ArrayObject.php') {
            echo 'getFilename()->' . $item->getFilename() . PHP_EOL;
            echo 'isDot()->' . $item->isDot() . PHP_EOL;
            echo '__toString()->' . $item->__toString() . PHP_EOL;
            echo 'getPath()->' . $item->getPath() . PHP_EOL;
            echo 'getPathname()->' . $item->getPathname() . PHP_EOL;
            echo 'getPerms()->' . $item->getPerms() . PHP_EOL;
            echo 'getInode()->' . $item->getInode() . PHP_EOL;
            echo 'getSize()->' . $item->getSize() . PHP_EOL;
            echo 'getOwner()->' . $item->getOwner() . PHP_EOL;
            echo 'getGroup()->' . $item->getGroup() . PHP_EOL;
            echo 'getATime()->' . $item->getATime() . PHP_EOL;
            echo 'getMTime()->' . $item->getMTime() . PHP_EOL;
            echo 'getCTime()->' . $item->getCTime() . PHP_EOL;
            echo 'getType()->' . $item->getType() . PHP_EOL;
            echo 'isWritable()->' . $item->isWritable() . PHP_EOL;
            echo 'isReadable()->' . $item->isReadable() . PHP_EOL;
            echo 'isExecutable()->' . $item->isExecutable() . PHP_EOL;
            echo 'isFile()->' . $item->isFile() . PHP_EOL;
            echo 'isDir()->' . $item->isDir() . PHP_EOL;
            echo 'isLink()->' . $item->isLink() . PHP_EOL;
            echo 'getFileInfo()->' . $item->getFileInfo() . PHP_EOL;
            echo 'getPathInfo()->' . $item->getPathInfo() . PHP_EOL;
            echo 'setFileClass()->' . $item->setFileClass() . PHP_EOL;
            echo 'setInfoClass()->' . $item->setInfoClass() . PHP_EOL;
            echo 'openFile()->' . $item->openFile() . PHP_EOL;
        }
    }
} catch (Exception $e) {
    echo 'No files Found!' . PHP_EOL;
}

FilterIterator

过滤指定条件的值,感觉效果和array_filter差不多,没用过

<?php

$animals = ['koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'NZ' => 'kiwi', 'kookaburra', 'platypus'];

class CullingIterator extends FilterIterator
{

    /*** The filteriterator takes  a iterator as param: ***/
    public function __construct(Iterator $it)
    {
        parent::__construct($it);
    }

    /*** check if key is numeric ***/
    function accept()
    {
        return is_numeric($this->key());
    }
}

/*** end of class ***/
$cull = new CullingIterator(new ArrayIterator($animals));

foreach ($cull as $key => $value) {
    echo $key . '=>' . $value . PHP_EOL;
}

IteratorAggregate

没使用过

<?php
class MyIteratorAggregate implements IteratorAggregate
{
    public $property1 = "Public property one";
    public $property2 = "Public property two";
    public $property3 = "Public property three";

    public $arr = [1, 2, 3, 4, 5, 6];

    public function __construct()
    {
        $this->property4 = "last property";
    }

    /**
     * 聚合迭代器本身不实现迭代的5个方法接口(rewind valid key current next),
     * 委托ArrayIterator实现
     *
     * @return ArrayIterator
     * @author jiangyi
     */
    public function getIterator()
    {
        //return new ArrayIterator($this);
        return new ArrayIterator($this->arr);
    }
}

$obj = new MyIteratorAggregate;

foreach ($obj as $key => $value) {
    var_dump($key, $value);
    echo "\n";
}

LimitIterator

没啥用处

/*** the offset value ***/
$offset = 3;

/*** the limit of records to show ***/
$limit = 2;

$array = ['koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus'];

$it = new LimitIterator(new ArrayIterator($array), $offset, $limit);

foreach ($it as $k => $v) {
    //echo $it->getPosition() . PHP_EOL;
    echo $k .'=>'.$v . PHP_EOL;
}

$array = ['koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus'];

$it = new LimitIterator(new ArrayIterator($array));

try {
    $it->seek(5);
    echo $it->current();
} catch (OutOfBoundsException $e) {
    echo $e->getMessage() . PHP_EOL;
}

RecursiveIteratorIterator

递归迭代器

<?php
$array = [
    ['name' => 'butch', 'sex' => 'm', 'breed' => 'boxer'],
    ['name' => 'fido', 'sex' => 'm', 'breed' => 'doberman'],
    ['name' => 'girly', 'sex' => 'f', 'breed' => 'poodle'],
];

foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key => $value) {
    echo $key . '->' . $value . PHP_EOL;
}

SimpleXMLIterator

可以用来解析XML

<?php

/*** a simple xml tree ***/
$xmlstring = <<<XML
<?xml version = "1.0" encoding="UTF-8" standalone="yes"?>
<document>
  <animal>
    <category id="48">
      <species>monotremes</species>
      <type>platypus</type>
      <name>Bruce</name>
    </category>
  </animal>
  <animal>
    <category id="4">
      <species>arachnid</species>
      <type>funnel web</type>
      <name>Bruce</name>
      <legs>8</legs>
    </category>
  </animal>
</document>
XML;

/*** a new simpleXML iterator object ***/
try {
    /*** a new simple xml iterator ***/
    $it = new SimpleXMLIterator($xmlstring);
    /*** a new limitIterator object ***/
    foreach (new RecursiveIteratorIterator($it, 1) as $name => $data) {
        //echo $name . '=>' . $data . PHP_EOL;
        if ($name == 'animal') {
            //var_dump($data);
        }
    }
} catch (Exception $e) {
    echo $e->getMessage();
}

try {
    /*** a new simpleXML iterator object ***/
    $sxi =  new SimpleXMLIterator($xmlstring);

    /*** set the xpath ***/
    $foo = $sxi->xpath('animal/category/species');

    /*** iterate over the xpath ***/
    foreach ($foo as $k=>$v)
    {
        echo $v.PHP_EOL;
    }
}
catch(Exception $e)
{
    echo $e->getMessage();
}

文章作者: 江湖义气
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 江湖义气 !
  目录