spl初识


layout: post
title: "spl初识"
date: 2016-05-13 20:26:58 +0800
comments: true
categories:


什么是SPL

SPL是Standard PHP Library(PHP标准库)的缩写。
根据官方定义,它是"a collection of interfaces and classes that are meant to solve standard problems"。但是,目前在使用中,SPL更多地被看作是一种使object(物体)模仿array(数组)行为的interfaces和classes。

SPL的常用数据结构

双向链表

  • SplDoublyLinkedList类
  • 操作
    • 当前节点操作:
      • rewind:使当前节点指向Buttom(头部)
      • next:指向下一个节点
      • prev:指向上一个节点
      • current:指向链表当前节点的指针,调用前需调用rewind,指向的节点被删除后会指向一个空节点
    • 增加节点操作:
      • push:向链表的顶部(尾部)插入一个节点
      • unshift:向链表的底部插入一个节点(头部)
    • 删除节点操作:
      • pop:获取链表中顶部(尾部)的节点并删除,不改变当前指针的位置
      • shift:删除连边底部(头部)的节点
    • 定位操作
      • bottom:获得链表底部(头部)的元素,指针位置不变
      • top:获得链表顶部(尾部)的元素,指针位置不变
    • 特定节点操作
      • offsetExists
      • offsetGet
      • offsetSet
      • offsetUnset
<?php

    $obj=new SplDoublyLinkedList();

    $obj->push(1);//把节点添加到顶部
    $obj->push(2);
    $obj->push(3);
    $obj->unshift(10);//将新的节点添加到底部(bottom)
    print_r($obj);
    $obj->rewind();//rewind操作用于把节点指针指向bottom所在的节点
    echo "current:".$obj->current()."\n"; //获取节点指针指向的节点(当前)
    $obj->next();//指向下一节点
    $obj->prev();//指向上一节点
    echo "next:".$obj->current()."\n";
    $obj->next();//指向下一节点
    $obj->next();//指向下一节点
    $obj->next();//指向下一节点
    $obj->next();//指向下一节点
    if($obj->current()){
      echo "Current node valid\n";
    }else{
      echo "Current node invalid\n";
    }
    if($obj->valid()){//如果当前节点有效,valid返回true
      echo "valid list";
    }else {
      echo "invalid list";
    }
    echo "pop value".$obj->pop()."\n";//把TOP位置的节点从链表中弹出。pop不影响指针指向的节点。如果pop指向的是top,调用POP后会指向NULL
    print_r($obj);
    echo "current:".$obj->current()."\n";
    $obj->shift();//把bottom位置的节点从链表中删除。并返回
    
?>

堆栈

  • 继承自SplDoublyLinkedList类的SplStack类
  • 先进后出
  • 操作
    • push:压入堆栈
    • pop:弹出堆栈
<?php
    $stack = new SplStack();
    $stack->push("a");
    $stack->push("b");
    $stack->push("c");
    print_r($stack);
    echo "Bottom:".$stack->bottom()."\n";
    echo "Top:".$stack->top()."\n";
    $stack->offsetSet(0,"C");//在Stack里面offset=0是TOP所在的位置,offset=1是top位置节点靠近bottom位置的相邻节点
    print_r($stack);
    $stack->rewind();
    echo "Current:".$stack->current()."\n";//双向链表的rewind和堆栈的rewind相反,堆栈的rewind使得当前指针指向TOP所在的位置,而双向链表的rewind指向bottom所在的位置
    $stack->next();
    echo "Current:".$stack->current()."\n";
    //遍历堆栈
    $stack->rewind();
    while($stack->valid()){
      echo $stack->key()."=>".$stack->current()."\n";
      $stack->next();
    }
    //删除堆栈
    $popObj = $stack->pop();
    echo "PopED object:".$popObj."\n";
    print_r($stack);
?>

队列

  • 继承自SplDoublyLinkedList类的SplQueue类
  • 先进先出
  • 操作
    • enqueue:进入队里
    • duqueue:退出对列
<?php
  $obj = new SplQueue();
  $obj->enqueue("a");//插入一个节点到TOP位置
  $obj->enqueue("b");
  $obj->enqueue("c");
  print_r($obj);
  echo "bottom:".$obj->bottom()."\n";
  echo "top:".$obj->top()."\n";
  $obj->offsetSet(0,"A");//队列里面的offset=0是bottom所在的位置
  print_r($obj);
  $obj->rewind();//队列的rewind指向bottom所在的位置
  echo "current:".$obj->current()."\n";
  while($obj->valid()){
    echo $obj->key()."=>".$obj->current()."\n";
    $obj->next();
  }
  echo "dequeue obj:".$obj->dequeue()."\n";//从队列中提取bottom位置的节点并删除
  print_r($obj);
?>

迭代器

什么是迭代器

通过某种同意的方式遍历链表或数组中的元素的过程叫做迭代遍历,而这种统一的遍历工具我们叫做迭代器

在PHP中迭代器是通过Iterator接口定义的。

常用的迭代器 ArrayIterator

  • 熟悉使用foreach和while语句通过ArrayIterator遍历数组的方法
  • 熟悉使用seek跳过某些元素的方法
  • 熟悉使用ArrayIerator进行排序的方法
<?php
    $fruits = array(
      "apple" => "appale value",
      "orange" => "orange value",
      "grape" => "grape value",
      "plum" => "plum value"
    );
    print_r($fruits);
    echo "use fruits directly \n";
    foreach ($fruits as $key => $value) {
      echo $key.":".$value."\n";
    }
    //使用ArrayIterator 遍历数组
    $obj = new ArrayObject($fruits);
    $it = $obj->getIterator();//获取迭代器
    echo "use ArrayIterator in foreach \n";
    foreach ($it as $key => $value) {
      echo $key.":".$value."\n";
    }
    echo "use ArrayIterator in while \n";
    $it->rewind();//ccurretn前需要rewind
    while ($it->valid()) {
      echo $it->key().":".$obj->current();
      $it->next();
    }
    //跳过某些元素进行打印
      echo "use seek befor while \n";
    $it->rewind();
    if($it->valid()){
      $it->seek(1);
      while ($it->valid()) {
        echo $it->key().":".$obj->current();
        $it->next();
      }
    }
    //实现排序
    echo "use ksort \n";
    $it->ksort();//对key字典序排序
    foreach ($it as $key => $value) {
      echo $key.":".$value."\n";
    }
    echo "use asort \n";
    $it->ksort();//对value字典序排序
    foreach ($it as $key => $value) {
      echo $key.":".$value."\n";
    }
?>

常用的迭代器 AppendIterator

  • AppendIterator能陆续遍历几个迭代器
    • 按顺序迭代访问几个不同的迭代器。 例如,希望在一些循环中迭代访问两个或多个组合。
<?php
  $array_a = new ArrayIterator(array("a","b","c","d"));
  $array_b = new ArrayIterator(array("e","f","g","h"));
  $it = new AppendIterator();
  $it->append($array_a);//通过append方法把迭代器对象添加到AppendIterator对象中
  $it->append($array_b);
  foreach ($it as $key => $value) {
    echo $value."\n";
  }
?>

常用的迭代器 MultipleIterator

  • MultipleIterator用于把多个Iterator里面的数据组合为一个整体来访问
<?php
  $idIter = new ArrayIterator(array("01","02","03"));
  $nameIter = new ArrayIterator(array("张三","李四","王五"));
  $ageIter = new ArrayIterator( array("22","23","24"));
  $mit = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);//知明当你拼凑起来过后Key也是一个Array
  $mit->attachIterator($idIter,"ID");
  $mit->attachIterator($nameIter,"NAME");
  $mit->attachIterator($ageIter,"AGE");
  foreach ($mit as  $value) {
    print_r($value);
  }
?>

常用的迭代器 FilesystemIterator

  • FilesystemIterator能遍历文件系统
<?php
    date_default_timezone_set("PRC");
    $it = new FilesystemIterator(".");
    foreach ($it as  $finfo) {
      printf("%s\t%s\t%8s\t%s\n",
      date("Y-m-d H:i:s",$finfo->getMTime()),
      $finfo->isDir()?"<DIR>":"",
      number_format($finfo->getSize()),
      $finfo->getFileName()
    );
    // echo $finfo->isDir()?"<DIR>":"",
      // echo date("Y-m-d H:i:s",$finfo->getMTime())."\n";
    }

?>

SPL基础接口

Countable

  • 继承了该接口的类可以直接调用count()得到元素个数。
<?php
    
    date_default_timezone_set("PRC");
    $array = array(
      array('name' => '张三','id'=>'5'),
      array('name' => '李四','id'=>'6'),
      array('name' => '王五','id'=>'7')
    );
    echo count($array)."\n";
    echo count($array[1])."\n";
?>

<?php
  class CountMe implements Countable{ //实现Countable接口,
    protected $_myCount=3;
    public function count(){
      return $this->_myCount;
    }
  }
  $obj = new CountMe();
  echo count($obj);//实现了Countable接口就能通过cout函数直接调用到之前定义好的Count方法
 ?>

OuterIterator

  • 如果想对迭代器进行一定的处理之后再返回,可以用这个接口
  • 继承自IteratorIterator这个类
<?php
    date_default_timezone_set("PRC");
    $array = array("value1","value2","value3","value4");
    print_r($array);
    $outerObj = new OuterImpl( new ArrayIterator($array));
    foreach ($outerObj as $key => $value) {
      # code...
      echo "++".$key."-".$value."\n";
    }
    class OuterImpl extends IteratorIterator{
      public function current(){
        return parent::current()."_tail";
      }
      public function key(){
        return "pre_".parent::key();
      }
    }

 ?>

RecursiveTterator

  • 可以对多次结构的迭代器进行迭代,比如遍历一棵树
  • 所有具有层次结构特点的数据都可以用这个接口遍历
    • 如文件夹
  • 关键方法
    • hasChildren :用于判断当前节点是否存在子节点
    • getChileren :用于得到当前节点子节点的迭代器
  • SPL中实现该接口的类
    • RecursiveArrayIterator,RecursiveCachingIterator等以 Recursive开头的类都能进行多层次结构化的遍历

SeekableIterator

  • 可以通过seek方法定位到集合里面的某个元素
  • seek方法的参数是元素的位置,从0开始

SPL基础函数的使用

Autoload

  • 为了初始化PHP中的类对象,需要通过一定的方法寻找到类的定义。通常情况下,类会定义在一个单独的文件中。
  • Autoload就是PHP找到这些文件的方法。
<?php
  /**
   *
   */
  class test
  {

    function __construct()
    {
      echo "Loading Class Libs/test.class.php\n";
    }
  }

?>

<?php
  class Test{
    public function __construct(){
      echo "Loading Class Libs/test.php\n";
    }
  }
 ?>

<?php
  spl_autoload_extensions(".class.php,.php");//设置autoload寻找php定义的类文件的扩展名,多个扩展名用逗号分开,前面的扩招名优先匹配
  set_include_path(get_include_path().PATH_SEPARATOR."libs/");//设置autoload寻找php定义的类文件的目录,多个目录用PATH_SEPARATOR分隔
  spl_autoload_register();//提示PHP使用autoload机制查找类定义
  new test();
?>

<?php
  function __autoload($class_name){//定义__autoload函数,可以不调用spl_autoload_register函数的情况下完成类的装载
    echo "__autoload class:".$class_name."\n";
    require_once("libs/".$class_name.".php");//装载类
  }
  function classLoader($class_name){//定义一个替换__autoload函数的类文件装载函数
    echo "classLoader() load class:".$class_name."\n";
      require_once("libs/".$class_name.".php");//装载类
  }
  spl_autoload_register("classLoader");//传入定义好的装载类的函数的名称替换__autoload函数
  new test();
 ?>

<?php
function classLoader($class_name){//定义一个替换__autoload函数的类文件装载函数
  echo "classLoader() load class:".$class_name."\n";
    set_include_path("lib/");
    spl_autoload($class_name);
}
spl_autoload_register("classLoader");//传入定义好的装载类的函数的名称替换__autoload函数
new test();
?>

SPL其他函数

  • 迭代器相关

    • iterator_apply :为迭代器中的每个元素调用一个用户自定义函数
    • iterator_count :计算迭代器元素个数
    • iterator_to_array :将迭代器的元素拷贝到数组
  • 类信息相关函数

    • class_implements 返回指定类实现的所有接口
      • 可以用instanceof判断某个对象时候实现某个接口或者某个类的实例
    • class_parents 返回指定类的父类
      • 如果继承了多次,会把所有父类都打印出来

文件处理类库

  • SPLFileInfo 用于获得文件的基本信息,比如修改时间,大小,目录等
  • SplFileObject用于操作文件的内容,比如读写
<?php
  $file = new SplFileInfo("temp.txt");
  echo "File is cerated at ".date("Y-m-d H:i:s",$file->getCTime())."\n";
  echo "File is modified at ".date("Y-m-d H:i:s",$file->getMTime())."\n";
  echo "File is size is".$file->getSize()."\n";
  //读取文件里面的内容
  $fileObj = $file->openFile("r");
  while ($fileObj->valid()) {
    echo $fileObj->fgets();//获取文件里慢的一行数据
  }
  $fileObj = NULL;
  $file = NULL;
?>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,172评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,346评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,788评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,299评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,409评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,467评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,476评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,262评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,699评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,994评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,167评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,499评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,149评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,387评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,028评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,055评论 2 352

推荐阅读更多精彩内容

  • 文/逢林 一次偶然机会,看到电影版的"等风来",被里面的独白深深吸引。在这里,我看到了曾经的自己和现在的自己。 ...
    一直思考的羽毛阅读 616评论 3 2
  • 莫怪常识难普及 太阳影子烙脑髓 自小灌输伟人颂 长大奴才定扎堆
    我心似箭阅读 318评论 0 0