课程:https://www.imooc.com/video/2511/0

测试结果来自php7.3+。
SPL含义:Standard PHP Library 标准PHP类库

1、SPL数据结构

stack overflow error 堆栈溢出错误

链表使用数据队列的原理,在类对象调用上可谓“纷繁复杂”。不管链表底层实现原理,直接继承 spldoublylinkedlist 使用就行。在实际中
SplStack、SplQueue继承自双向链表(类:SplDoublyLinkedList),这里序列形象赖于 Obj->push()方法添加 所打印的序列。

a.SplDoublyLinkedList双向链表

官方接口

class SplDoublyLinkedList implements Iterator, Countable, ArrayAccess, Serializable {
  -add($index, $newval)
  -push($value)/pop()                                --尾部 +-end
  -unshift($value)/shifts()                          --顶部 +-beginning
  -top()                                             --尾部 end
  -bottom()                                          --开头 beginning
  -count()
  -isEmpty()
  -setIteratorMode($mode)
  -getIteratorMode()
  -offsetExists($index)
  -offsetGet($index)
  -offsetSet($index, $newval)
  -offsetUnset($index)                                --删除指定索引,并重新连接[排序]
  -rewind()                                           --back to the start
  -current()
  -key()                                              --current的index
  -next()
  -prev()
  -valid()
  -serialize()
  -unserialize(string $serialized)
  -__serialize()
  -__unserialize(array $data)
}

SplDoublyLinkedList0SplDoublyLinkedList.php

SplDoublyLinkedList: 
SplDoublyLinkedList Object
(
    [flags:SplDoublyLinkedList:private] => 0
    [dllist:SplDoublyLinkedList:private] => Array
        (
        )

)
is valid ? bool(false)
push:1-2-3; unshift:10: 
SplDoublyLinkedList Object
(
    [flags:SplDoublyLinkedList:private] => 0
    [dllist:SplDoublyLinkedList:private] => Array
        (
            [0] => 10       --unshift一个10
            [1] => 1        --push添加1,2,3从顶部-->底部
            [2] => 2
            [3] => 3
        )

)

44current:--next node:
49rewind, current:10, 
next, node:1, 
next, node:2
62current pop?:3            --pop固定的底部删除3
current:2
push:X; unshift:Y:          --底部加X,顶部Y
current pop:X               --pop固定的底部删除X
68current:2
SplDoublyLinkedList Object
(
    [flags:SplDoublyLinkedList:private] => 0
    [dllist:SplDoublyLinkedList:private] => Array
        (
            [0] => Y
            [1] => 10
            [2] => 1
            [3] => 2
        )

)

offsetGet: 3 == 2; top:2; bottom:Y
SplDoublyLinkedList Object
(
    [flags:SplDoublyLinkedList:private] => 0
    [dllist:SplDoublyLinkedList:private] => Array
        (
            [0] => Y
            [1] => 10
            [2] => 1
            [3] => 2
        )

)
rewind顺序打印: 
Y,10,1,2,                   --打印从顶部到底部
0

b.SplQueue队列、Slack栈

SplQueue 1SplQueue.php 与SplDoublyLinkedList基本相同:

SplQueue: 
SplQueue Object
(
    [flags:SplDoublyLinkedList:private] => 4
    [dllist:SplDoublyLinkedList:private] => Array
        (
        )

)
is valid ? bool(false)
push:1-2-3; unshift:10: 
SplQueue Object
(
    [flags:SplDoublyLinkedList:private] => 4
    [dllist:SplDoublyLinkedList:private] => Array
        (
            [0] => 10
            [1] => 1
            [2] => 2
            [3] => 3
        )

)

44current:--next node:
49rewind, current:10, 
next, node:1, 
next, node:2
62current pop?:3
current:2
push:X; unshift:Y: 
current pop:X
68current:2
SplQueue Object
(
    [flags:SplDoublyLinkedList:private] => 4
    [dllist:SplDoublyLinkedList:private] => Array
        (
            [0] => Y
            [1] => 10
            [2] => 1
            [3] => 2
        )

)

offsetGet: 3 == 2; top:2; bottom:Y
SplQueue Object
(
    [flags:SplDoublyLinkedList:private] => 4
    [dllist:SplDoublyLinkedList:private] => Array
        (
            [0] => Y
            [1] => 10
            [2] => 1
            [3] => 2
        )

)
rewind顺序打印: 
Y,10,1,2,
4

SplStack 2SplStack.php

SplStack: 
SplStack Object
(
    [flags:SplDoublyLinkedList:private] => 6
    [dllist:SplDoublyLinkedList:private] => Array
        (
        )

)
is valid ? bool(false)

push:1-2-3; unshift:10: 
SplStack Object
(
    [flags:SplDoublyLinkedList:private] => 6
    [dllist:SplDoublyLinkedList:private] => Array
        (
            [0] => 10
            [1] => 1
            [2] => 2
            [3] => 3
        )

)

44current:--next node:

49rewind, current:3,                --rewind到尾部
next, node:2,                       --next从底部到顶部
next, node:1
62current pop?:3
current:1
push:X; unshift:Y: 
current pop:X
68current:1
SplStack Object
(
    [flags:SplDoublyLinkedList:private] => 6
    [dllist:SplDoublyLinkedList:private] => Array
        (
            [0] => Y
            [1] => 10
            [2] => 1
            [3] => 2
        )

)

offsetGet: 3 == Y; top:2; bottom:Y
SplStack Object
(
    [flags:SplDoublyLinkedList:private] => 6
    [dllist:SplDoublyLinkedList:private] => Array
        (
            [0] => Y
            [1] => 10
            [2] => 1
            [3] => 2
        )

)
rewind顺序打印: 
2,1,10,Y,                           --打印从底部开始到顶部
6

c.SplDLL.0|SplQueue.4|SplStack.6小结

SplDoublyLinkedList::setIteratorMode 参数:

There are two orthogonal sets of modes that can be set:
◦ The direction of the iteration 迭代的方向(either one or the other):
 ◦SplDoublyLinkedList::IT_MODE_LIFO (Stack style) 2
 ◦SplDoublyLinkedList::IT_MODE_FIFO (Queue style) 0

◦ The behavior of the iterator 迭代器的行为(either one or the other):
 ◦SplDoublyLinkedList::IT_MODE_DELETE (Elements are deleted by the iterator 元素被迭代器删除) 1
 ◦SplDoublyLinkedList::IT_MODE_KEEP (Elements are traversed by the iterator 元素由迭代器遍历) 0

The default mode is: SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_KEEP
Iteration Direction
SplDoublyLinkedList::IT_MODE_LIFO
    The list will be iterated in a last in, first out order, like a stack.
    该列表将按“最后入,先出”的顺序迭代,就像栈一样。  [First in, First out.先进先出]
SplDoublyLinkedList::IT_MODE_FIFO
    The list will be iterated in a first in, first out order, like a queue.
    该列表将按照先入先出的顺序迭代,就像队列一样. [LIFO: Last in, First out.后进先出]

const IT_MODE_LIFO = 2;
const IT_MODE_FIFO = 0;
const IT_MODE_DELETE = 1;
const IT_MODE_KEEP = 0;

官方接口:

class SplQueue extends SplDoublyLinkedList {
  -enqueue($value)                                        --入列 add to queue
  -dequeue()                                              --出列 dequeue a node
}
class SplStack extends SplDoublyLinkedList {
  -esetIteratorMode($mode)                                 --设置迭代模式(方向)
}

上面来自关联接口:phpstorm//stubs/SPL/SPL_c1.php 和php官网。

从C++学习基础归来,可以看到:系统分配堆、先进后出,自定义new栈、随进随出【先入必先出、不然找不到;并且执行段结束了】。
即堆[Slack]是系统指定的逆序列,堆[Heap]是随进随出的正序列。

异同点:
rewind()、next()、prev() ==> 双链表和queue是start在上、slack在下
top\bottom\add\push\pop等相同

2、迭代器

a.ArrayIterator 数组转换链表

This iterator allows to unset and modify values and keys while iteratingover Arrays and Objects. 这个迭代器允许在遍历数组或对象时,取消设置、修改值和键。
5ArrayIterator.php

//example 1; 普通数组迭代
$fruits = array(
    "apple" => "yummy",
    "orange" => "ah ya, nice",
    "grape" => "wow, I love it!",
    "plum" => "nah, not me"
);
$obj = new ArrayObject( $fruits );
$it = $obj->getIterator();
echo "Iterating over: " . $obj->count() . " values\n";
while( $it->valid() )
{
    echo $it->key() . "=" . $it->current() . "\n";
    $it->next();
}
foreach ($it as $key=>$val)
echo $key.":".$val."\n";

//example 2: 两数组健值组合[array_combine]
$fruits = array(
                "apple" => "yummy",
                "orange" => "ah ya, nice",
                "grape" => "wow, I love it!",
                 "plum" => "nah, not me"
                );

$veg = array("potato" => "chips", "carrot" => "soup");
$grocery = array($fruits, $veg);
$obj = new ArrayObject( $grocery );
$it = new RecursiveIteratorIterator( new RecursiveArrayIterator($grocery));
foreach ($it as $key=>$val)
    echo $key.":".$val."\n";

b.AppendIterator 迭代器合并

An Iterator that iterates over several iterators one after the other. 一个在多个迭代器拼接的新迭代器[array_merge_recursive],允许重复值。
6AppendIterator.php

//array_merge_recursive
$array_a = array(
                "apple" => "yummy",
                "orange" => "ah ya, nice",
                "grape" => "wow, I love it!",
                 "plum" => "nah, not me"
                );
$array_b = array("potato" => "chips", "plum" => "soup");
$it = new AppendIterator();
$it->append(new ArrayIterator($array_a));
$it->append(new ArrayIterator($array_b));
foreach($it as $key => $value){
    echo $key. ': '. $value;
}
/*
apple: yummy
orange: ah ya, nice
grape: wow, I love it!
plum: nah, not me
potato: chips
plum: soup

 */

c.MultipleIterator 对照分组迭代器

An Iterator that sequentially iterates over all attached iterators.一个迭代器按顺序遍历所有附加迭代器的迭代器。
7MultipleIterator.php

//键值同步分离
$it1 = new ArrayIterator(array(1,2,3,4,5));    //对照只列出前3个
$it2 = new ArrayIterator(array(4,5,6));
$multipleIterator = new MultipleIterator(MultipleIterator::MIT_NEED_ALL|MultipleIterator::MIT_KEYS_ASSOC);

$multipleIterator->attachIterator($it1, 1);
$multipleIterator->attachIterator($it2, 'second');

foreach ($multipleIterator as $key => $value) {
    echo "Key"; var_dump($key);
    echo "Value"; var_dump($value);
    echo "---next---\n";
}
/*
Keyarray(2) {
  [1]=>
  int(0)
  ["second"]=>
  int(0)
}
Valuearray(2) {
  [1]=>
  int(1)
  ["second"]=>
  int(4)
}
---next---
Keyarray(2) {
  [1]=>
  int(1)
  ["second"]=>
  int(1)
}
Valuearray(2) {
  [1]=>
  int(2)
  ["second"]=>
  int(5)
}
---next---
Keyarray(2) {
  [1]=>
  int(2)
  ["second"]=>
  int(2)
}
Valuearray(2) {
  [1]=>
  int(3)
  ["second"]=>
  int(6)
}
---next---


 */

d.FileSystemIterator 文件浏览迭代器: 列表|文本内容

This abstract iterator filters out unwanted values. This class should be extended toimplement custom iterator filters. The FilterIterator::accept()must be implemented in the subclass. 这个抽象的迭代器过滤掉不需要的值。应该扩展这个类来实现自定义迭代器过滤器。必须在子类中实现FilterIterator::accept()。
8FileSystemIterator.php

//文件夹迭代
$it = new FilesystemIterator('.');
foreach ($it as $fInfo){
    print_r([
        'mt'=>date('Y-m-d H:i:s', $fInfo->getMTime()),
        'fs'=>$fInfo->getSize()
    ]);
}

## 逐行迭代读取文件
// $file = new \SplFileInfo('tree.php');
// $fileObj = $file->openFile('r');
$fileObj = new \SplFileObject('tree.php', 'r'); //与上面等价
while($fileObj->valid()){
    echo $fileObj->fgets(); 
}
//关闭文件对象
$fileObj = null;
$file = null;

3、迭代器接口

a. Iterator 基础迭代接口

作为口标准:

//Traversable可否认的[接口,以检测是否可以使用foreach遍历类]
Iterator  extends Traversable { 
    abstract public current( void) : mixed
    abstract public key( void) : scalar
    abstract public next( void) : void
    abstract public rewind( void) : void
    abstract public valid( void) : bool
}

class myIterator implements Iterator {  
    private $position = 0;  
    private $array = array(  
        "firstelement",  
        "secondelement",  
        "lastelement",  
    );      
    public function __construct() {  
        $this->position = 0;  
    }    
    public function rewind() {  
        $this->position = 0;  
    }    
    public function current() {  
        return $this->array[$this->position];  
    }    
    public function key() {  
        return $this->position;  
    }    
    public function next() {  
        ++$this->position;  
    }    
    public function valid() { 
        return isset($this->array[$this->position]);  
    }  
}`

b. Countable 类可计数接口

Classes implementing Countable can be used with the count()function. 实现Countable的类可以与count()函数一起使用。

class CountMe implements Countable
{
    public function count(){ return 3;}
}
echo count(new CountMe()); //3

c.OuterIterator 类迭代接口

extends IteratorIterator => parent::current(),parent::key()
Classes implementing OuterIterator can be used to iterateover iterators. 实现OuterIterator的类可用于在迭代器上迭代。

class OuterTmpl extends IteratorIterator
{
    public function current(){
        return (parent::current() * parent::current()).'_**_'. parent::key();
    }
    public function key(){
        return 'key? '. (parent::key() * 2);
    }
}
$array = [1,3,5,7,9];
$outerObj = new OuterTmpl(new ArrayIterator($array));
foreach($outerObj as $key => $value){
    echo $key. ': '. $value, PHP_EOL;
}

4、其他函数

sql_autoload_register 注册函数

注册给定的函数作为 __autoload 的实现。
把类放到系统调用区。

spl_autoload_extensions(".php, .inc");
set_include_path(get_include_path() . PATH_SEPARATOR .'libs/');
var_dump( get_include_path() );
spl_autoload_register();
var_dump(new test());
var_dump(new PEople()); //类名加载不区分大小写,这里类名*文件名*小写【大写加载不了,还不清楚】

function ClassLoader($class_name){
    echo "ClassLoader load class: ". $class_name. "<br/>";
    set include_path("libs/");
    spl_autoload($class_name); //须要显示调用
}
spl_autoload_register("ClassLoader"); //或数组['类名/类实例'=>'方法']
class_implements($class)

返回指定的类实现的所有接口

iterator_apply($it, callable $function[, array $args])

为迭代器中的每个元素调用一个函数[array_walk]

$it = new ArrayIterator(["Apples", "Bananas", "Cherries"]);
iterator_apply($it, function (Iterator $iterator) {
    echo strtoupper($iterator->current()), PHP_EOL;
    return TRUE;
}, array($it));
foreach($it as $key => $value){
    echo $key. ': '. $value, PHP_EOL;
}
iterator_count($it)

返回迭代长度

iterator_to_array($it[, $use_keys = true])

将迭代器中的元素拷贝到数组

实例测试代码上传:
https://github.com/cffycls/cluster/tree/master/html/spl


沧浪水
97 声望12 粉丝

引用和评论

0 条评论