PHP SPL入了个门

SPL_LOGO
说在最前面
最近决定在慢慢涉及到PHP的方方面面,所以最近这样的文章会比较多,这篇就记录下SPL相关的内容,SPL也就是Standard PHP Library的缩写,打开官方SPL相关的介绍,内容还是很多的,当然啦,既然是标准库肯定内容会不少,具体按照类别来区分主要包含:

,这篇文章就只简单介绍几个经常使用的。

不介绍的并不是不重要,对于实现一些框架级别的工程时,SPL经常被用到,所以勤翻手册。

ArrayAccess

<?php

class Foo implements ArrayAccess{
    private $properties = [];

    public function offsetExists($offset)
    {
        return isset($this->properties[$offset]);
    }
    public function offsetGet($offset)
    {
        return isset($this->properties[$offset]) 
            ? $this->properties[$offset] 
            : '';
    }

    public function offsetSet($offset, $value)
    {
        if($offset){
            $this->properties[$offset] = $value;
        }else{
            $this->properties[] = $value;
        }
    }

    public function offsetUnset($offset)
    {
        unset($this->properties[$offset]);
    }

}
$foo = new Foo();
$foo->offsetSet("key1", "value1");
$foo->offsetSet("key2", "value2");
echo $foo->offsetGet("key1");
echo $foo->offsetGet("key2");
//output
/**
* value1value2
*/

我的理解
在我看来,这个ArrayAccess接口有点类似于重载,将PHP的弱类型的特性提供了标准,但这个命名似乎有点让人迷惑。

ArrayAccess的实际应用
Laravel核心的容器类Container.php

Countable

<?php

class Foo implements Countable{

    private $_count = 10;
    public function count()
    {
        return $this->_count;
    }
}

$foo = new Foo;
//由于Foo类继承了Countable,count($foo)时将自动调用Foo类本身的count()
echo count($foo);

我的理解
Countable对于实现ORM比较有用,比如我们通过一些框架的Model类做查询时$ret = Model->select();,返回的$ret多数是Object,而不是Array,而这时如果我想知道结果集中有多少条记录时会count($ret);,为保证正确返回记录数,则需要实现Countable接口,重写count()。

Countable的实际应用
Laravel中路由集合类RouteCollection.php

Iterator – 迭代器

<?php

class Foo implements Iterator
{
    private $_position = 0;
    private $_data = array(
        '1',
        '2',
        '3',
    );

    public function current ()
    {
        var_dump(__METHOD__);
        return $this->_data[$this->_position];
    }

    public function key ()
    {
        var_dump(__METHOD__);
        return $this->_position;
    }

    public function next ()
    {
        var_dump(__METHOD__);
        ++ $this->_position;
    }

    public function rewind ()
    {
        var_dump(__METHOD__);
        $this->_position = 0;
    }

    public function valid ()
    {
        var_dump(__METHOD__);
        return isset($this->_data[$this->_position]);
    }
}

$foo = new Foo;
//由于Foo继承Iterator,所以当调用foreach($foo)时,将自动调用current()、next()等方法以实现遍历
foreach($foo as $key => $value){
    var_dump($key, $value);
}
//output
/**
*string(11) "Foo::rewind"
*string(10) "Foo::valid"
*string(12) "Foo::current"
*string(8) "Foo::key"
*int(0)
*string(1) "1"
*string(9) "Foo::next"
*string(10) "Foo::valid"
*string(12) "Foo::current"
*string(8) "Foo::key"
*int(1)
*string(1) "2"
*string(9) "Foo::next"
*string(10) "Foo::valid"
*string(12) "Foo::current"
*string(8) "Foo::key"
*int(2)
*string(1) "3"
*string(9) "Foo::next"
*string(10) "Foo::valid"
*/

我的理解
Iterator是一种最基本的迭代器,通过实现Iterator几个简单的方法(current(),key()…)自动实现了foreach()的操作,而由于这些方法都是由我们自己重写的,所以可以在最基本、最简陋的foreach()基础上实现想做的事情。
上面说了Iterator是最基本的一种迭代器,而SPL中有众多不同的迭代器,官方给出了迭代器的树型结构spl.iterators

IteratorAggregate – 聚合迭代器

<?php

class Foo implements IteratorAggregate
{
    /**
     * must public
     */
    public $_property1 = 1;
    public $_property2 = 2;
    public $_property3 = 3;

    /**
     * called when foreach
     */
    public function getIterator()
    {
        return new ArrayIterator($this);
    }
}

$foo = new Foo;
foreach($foo as $key => $value){
    var_dump($key, $value);
}
//output
/**
*string(10) "_property1"
*int(1)
*string(10) "_property2"
*int(2)
*string(10) "_property3"
*int(3)
*/

我的理解
IteratorAggregate是另一种更加简单的迭代器,具体实现起来要比Iterator简单、方便(具体不用实现那么多的接口[/偷笑]),只需要实现一个getIterator()即可。
IteratorAggregate接口通常与ArrayIterator搭配使用。

IteratorAggregate的实际应用
Laravel中路由集合类RouteCollection.php
比如在此类中,下面就继承了IteratorAggregate接口,并实现了getIterator()以获得所有路由

/**
 * Get an iterator for the items.
 *
 * @return \ArrayIterator
 */
public function getIterator()
{
    return new ArrayIterator($this->getRoutes());
}

最后
有关SPL的内容,就介绍这简单的几个,具体还要慢慢学习,慢慢看手册,慢慢实践。

PHP SPL入了个门
Tags:                     

发表评论

电子邮件地址不会被公开。 必填项已用*标注