//SPL:PHP标准库,Standand PHP Library 解决常见问题的一组接口与类的集合
//双向链表
微博用户A <--关注--> 微博用户B <--关注--> 微博用户C //如果是单向的,则为单向链表
注:最先添加到列表当中的节点:Bottom/head
最后添加到列表当中的节点:Top,也称为尾部
链表指针:是当前关注的节点的标识,可以指向任意节点
当前节点:链表指针指向的节点
节点的组成:节点名称key/offset 节点数据value
SqlDoublylinkedList类
操作:
当前节点操作:rewind(第一个节点),current(当前节点),next(下一个节点),prev(前一个节点)
增加节点操作:push,array_unshift
删除节点操作:pop,shift
定位操作: bottom,top
特定节点操作:offsetExists,offsetGet,offsetSet,offsetUnset
双向链表在SPL中的实现:PHP -f SqlDoublylinkedList.php可以在cmd中测试
$obj=new SqlDoublylinkedList();
$obj->push(1); //将1推入链表,也就是添加到顶部top
$obj->push(2);
$obj->push(3);
$obj->unshift(10); //反向将10推入链表,也就是10将键值0占据,也就是添加到底部botton
$obj->rewind(); //调用rewind后,才会有指针,也就是才有current(当前指针的节点值),将指针指向bottom
$obj->next(); //指针向后移动一次
$obj->prev(); //指针向前移动一次
echo "current:".$obj->current(); //获取当前节点的值
if($obj->current){ //判断是否移动完毕
echo "current node validn";
}else{
echo "current node invalidn";
}
if($obj->valid()){ //可以直接用内置函数判断是不是指针移动完毕(判断节点是否有效)
echo "valid list n";
}
$obj->pop(); //删除离top最近的节点
$obj->shift(); //删除bottom所在位置的节点
双向链表总结:两头皆可操作
//堆栈 算是双向链表的衍生
3号圆盘 |
5号圆盘 |
7号圆盘 |
SqlStack类继承自SqlDoublylinkedList类
操作:
push:压入堆栈(存入)
pop: 退出堆栈(取出)
代码实现:
$Stack = new SqlStack();
$stack->push('a'); //加入a,b,c
$stack->push('b');
$stack->push('c');
print_r($stack);
echo $stack->bottom;
echo $stack->top;
echo $stack->offsetSet(0,'C'); //堆栈的offset=0是top所在的位置,offset=1是靠近top所在的节点,而在双向链表中相反!!!
//将offset=0的键值对应的value设为C
$stack->rewind();
$stack->current(); //rewind()之后,堆栈指向top位置,双向链表指向底部bottom
$stack->next(); //会指向靠近bottom的方向
//遍历堆栈
$stck->rewind();
while($stck->valid()){
echo $stack->key()."=>".$stack->current()."n";
$stack->next();
}
//删除堆栈数据
$popobj = $stack->pop();
echo "被删除的元素".$popobj;
堆栈总结:只能从top操作,很多函数如next,prev指向的方向与双向链表相反
//队列:排队打饭一样,先到先打,与堆栈恰恰相反
SqlQueue类也继承自SqlDoublylinkedList类
enqueue:进入队列
dequeue:退出队列
代码实现:
$obj = new SqlQueue();
$obj->enqueue('a'); //将abc加入到队列
$obj->enqueue('b');
$obj->enqueue('c');
echo "bottom: ".$obj->bottom."n";
echo "top: ".$obj->top."n";
$obj->offsetSet(0,'A'); //队列里面0为bottom
$obj->rewind(); //队列里面指向bottom
遍历队列
while($obj->valid()){
echo %$obj->key()."=>".$obj->current()."n";
$obj->next();
}
//删除
$delobj=>$obj->dequeue();
队列小结:一切以先来先出为原则。
/
常用的迭代器三:MultipleIterator----------------------------------------------------------------------(将多个Iterator里面的数据组合成为一个整体来访问)
代码实现:
$idIter = new ArrayIterator(array('01','02','03'));
$nameIter = new ArrayIterator(array('张三','李四','王五'));
$ageIter = new ArrayIterator(array('21','23','25'));
$mit = new MultipleIterator(MultipleIterator::MIT_KEY_ASSOC);
$mit->attachIterator($idIter,"ID");
$mit->attachIterator($nameIter,"NAME");
$mit->attachIterator($ageIter,"AGE");
foreach($mit as $value){
print_r($value);
}
常用的迭代器四:FilesystemIterator----------------------------------------------------------------------(遍历文件系统)
代码实现:
date_default_timezone_get('PRC');
$it = new FilesystemIterator('.'); //.表示当前目录
foreach ($it as $finfo){
printf("%st%s%8st%sn",
date("Y-m-d H:i:s",$finfo->getMTime())."n", //打印出当前文件夹下的所有文件的格式化时间
$finfo->isDir()?
number_format($finfo->getSize()), //将文件大小格式化,每3位加逗号
$finfo->getFileName()
);
}
//******************************************SPL的基础接口************************************************************
1:理解Countable/OuterIterator/RecursiveIterator/SeekableIterator等4个接口的概念
2:熟练掌握Countable接口的使用
Countable:继承该接口的类可以直接调用count得到元素的个数
OuterIterator:如果想对迭代器进行一定的处理之后再返回,可以使用这个接口
RecursiveIterator:可以对多层结构的迭代器进行迭代,比如遍历一棵树
SeekableIterator:通过seek方法定位到集合里面的某一个特定元素
******************************************Countable接口*****************************************************
count(array('name'=>'Peter','id'=>'2'))
date_default_timezone_get('PRC')
$array=array (
array('name'=>'Jonathon','id'=>'2'),
array('name'=>'SEM','id'=>'2'),
array('name'=>'Tom','id'=>'2')
)
echo count($array); //3 自数组个数
echo count($array[1]); //2 第二个子数字的元素个数
class CountMe implements Countable {
protected $_myCount=3;
public function count(){
return $this->_myCount;
}
}
$obj = new CountMe();
echo count($obj); //不加implements Countable时显示1,加后显示为3!!!!!!!!!!
******************************************OuterIterator接口*****************************************************
如果想对迭代器进行一定的处理之后再返回,可以用这个接口
IteratorIterator类时OuterIterator类的实现,扩展的时候可以直接继承IteratorIterator
代码实现:
date_default_timezone_get('PRC');
$array=['Value1','Vlaue2','Vlaue3','Vlaue4'];
$outerObj = new OuterImpl(new Arrayi($array);
forach($outerObj as $key=>$value){
echo "++".$key."-".$vale."n"; //$key会显示成Pre_0,$value会显示成Value1_tail
}
class OuterImpl extends IteratorIterator{
public function current(){ //value
return parent::current().'_tail';
}
public function key(){ //key
return "Pre_".parent::key();
}
}
******************************************RecursiveIterator接口*****************************************************
见doc的一张图,粗讲。
******************************************SeekableIterator接口*****************************************************
见doc的一张图,粗讲。
//******************************************SPL函数的使用************************************************************
1:
Autoload:为了初始化PHP中的类对象,需要通过一定的方法寻找类的定义。通常情况下,类会定义在一个单独的文件中。
Aotuload就是PHP找到这些类文件的方法。
class Test{
public function __construct(){
echo "Loading Class libs/Test.phpn";
}
}
spl_autoload_extensions('.class.php,.php'); //会自动加载Test.class.php,也可以设置为.php,两者也可俱在
set_include_path(get_include_path().PATH_SEPARATOR."libs/"); //将类的位置这只在libs/下
//设置autoload寻找定义的类文件的目录,多个目录用_PATH_SEPARATOR进行分割。
spl_autoload_register(); //PHP使用Autoload机制查找类定义
new Test();
?>
2:
__autoload装载类
function __autoload($class_name){
echo "__autoload class :".$class_name."n";
require_once("libs/".$class_name.'.php');
}
//也可以自定义一个类似__autoload方法
function classLoader($class_name){
echo "classLoader class :".$class_name."n";
require_once("libs/".$class_name.'.php');
}
spl_autoload_register('classLoader'); //这样也就将__autoload方法重命名了,将__autoload方法顶替了
new Test();
注:还可以将require_once替换成set_include_path顶替,代码实现如下:
function classLoader($class_name){
echo "classLoader class :".$class_name."n";
set_include_path("libs/");
spl_autoload($class_name); //当我们不用require或者require_once载入类文件的时候,而是想通过系统查找include_path来装载类时,必须显式调用spl_autoload函数,参数是类的名称来重启类文件的自动查找
}
spl_autoload_register('classLoader');
new Test();
*************************************
总结:类载入的基本流程,参见doc文档一图。
*************************************
//******************************************SPL的文件处理类库************************************************************
两个类库
实现代码:
date_default_timezone_get("PRC");
$file = new SqlFileInfo("tmp.txt");
echo "File is created 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";
//读取里面的内容
$fileObj = $file->openFile("r"); //以读的方式打开一个文件
while($fileObj->valid()){
echo $fileObj->fgets(); //fget获取文件里面的一行数据
}
$openObj = null; //用于关闭打开的文件
$file null;
这里文件的读入方式是面向对象的,比fopen之类的函数要简洁,提倡使用!
****************************************************************************************************************
课程总结:略
****************************************************************************************************************
?>



