课程准备知识
熟悉和了解数据结构的节本概念
熟悉PHP代码的编写
熟悉面向对象的概念
什么是 SPL
SPL的基本框架
SPL的常用数据结构
SPL的常用迭代器
SPL的接口
SPL函数的使用
SPL的文件处理类库
SPL标准PHP库
它是用于解决典型(常见)问题的一组接口与类的集合。
common problem
数学建模/数据结构
解决数据怎么存储的问题(病人信息怎么存储)
元素遍历
数据怎么查看的问题(病人的信息怎么看)
常用方法的统一调用
通用方法(数组、集合的大小)
自定义遍历
类定义在自动装载
让PHP程序适应大型项目的管理要求,把功能的实现分散到不同文件中。
2-1 SPL里面的数据结构
本章课程适合对数据结构理解不是很熟悉的同学
本章课程不需要有非常强的PHP基础
如果您对于双向链表、堆栈、队列、堆等数据结构概念都比较熟悉,请跳过本章内容
教学目的
理解各种数据结构
学习如何使用SPL使用各种数据结构
什么是数据结构
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。
解决的是软件开发过程中的数据如何存储和表示的问题。
新浪微博里面某个用户的数据怎么存?
SPL提供哪些数据结构呢?
双向链表、堆栈、队列、堆、降序堆、升序堆、优先级队列、定长数组、对象容器
2-1双向列表
基本概念
抽象一下
bottom:最先添加到链表中的结点叫做bottom(底部),也成为头部(head)
top:最后添加到链表中的结点叫做top(顶部),也成为尾部
链表指针:是一个当前关注的结点的标志,可以指向任意结点。
当前结点:链表指针指向的结点成为当前结点。
结点1:喜欢 结点名称和节点数据
结点名称:可以在链表中位移标识一个结点的名称,通常我们又称为结点的key或者offset
结点数据:存放在链表中的应用数据,我们通常称为value
数据结构值SPLDoublyLinkedList类
当前结点操作
rewind
current
next
prev
增加结点操作
push
unshift
增加结点操作
pop
shift
定位操作
bottom
top
定位操作
bottom
top
特定结点操作
offsetExists
offsetGet
offsetSet
offsetUnset
<?php
$obj=new SplDoublyLinkedList();
print_r($obj);
?>
<?php
$obj=new SplDoublyLinkedList();
$obj->push(1);
print_r($obj);
?>
unshift把一个元素添加到bottom的位置
push是把新的结点数据添加到列表的top顶部
unshift是把新的结点数据添加到链表的底部bottom
current是空的,说明一个也没有指向
<?php
$obj=new SplDoublyLinkedList();
$obj->push(1);
$obj->push(2);
$obj->push(3);
$obj->push(4);
$obj->unshift(10);
print_r($obj);
echo 'current : '.$obj->current();
?>
有了rewind之后,current才有意义
rewind用于比结点指针指向bottom结点
current用于获取结点指针指向的节点
$obj->next();
echo 'current : '.$obj->current()."\n";
pop操作不影响current
如果pop删除的是当前的元素的话,current会指向一个空的结点
shift是把bottom位置的结点从链表中删除,并返回
2-6堆栈的简介
先进后出
first in last out
继承自SplDoublyLinkedList类的SplStack类
操作
push:压入堆栈(存入)
pop:退出堆栈(取出)
6表示先进先出
<?php
$stack = new SplStack();
$stack->push('a');
$stack->push('b');
$stack->push('c');
print_r($stack);
$stack->bottom();
$stack->top();
$stack->offsetSet(0,'C');
//堆栈的offset=0是top所在的位置,offset=1是top位置结点靠近bottom位置的相邻结点,以此类推
print_r($stack);
?>
$stack->rewind(); //双向链表的rewind
echo "current: ".$stack->current()."\n";
$stack->next();
echo "current: ".$stack->current()."\n"; //会指向b
$stack->rewind();
while($stack->valid()){
echo $stack->key()."current is:".$stack.current()."\n";
$stack->next();
}
这是一个遍历的过程
next不从链表中删除数据
$popObj=
2-8队列
队列和堆栈刚好相反,最先进入队列的元素会最先走出队列
就想排队打饭,排在最前面的人,总是最先能够打到饭
继承自SPLdoublylinkedlist类的splqueue类
操作enqueue 进入队列
dequeue 退出队列
<?php
$obj = new SplQueue();
$obj->enqueue('a');
$obj->enqueue('b');
$obj->enqueue('c');
$obj->enqueue('d');
print_r($obj);
?>
echo "bottom: ".$obj->bottom()."\n";
echo "top: ".$obj->top()."\n";
$obj->offsetSet(0,'A');
print_r($obj);
dequeue是从队列中提取bottom位置的结点,并返回。同时从队列里面删除钙元素。
第三章迭代器
以代码讲解尾注,通过实例讲解各个迭代器的用法
教学目的
理解各种常用的迭代器
掌握如何使用常用的迭代器
通过某种同一的方式遍历链表或者数组中的元素的过程叫做迭代遍历,而这种同一的便利工具我们叫做迭代器。
PHP中迭代器是通过iterator接口定义的
<?php
$fruits = array(
"apple" => "apple value",
"banana" => "orange value",
"grape" => "grape value",
"plum" => "plum value"
);
print_r($fruits);
echo "********user fruits directly";
foreach($fruits as $key => $values){
echo $key." aaaa ".$values;
}
?>
$obj = new ArrayObject($fruits);
$it = $obj->getIterator();
foreach($fruits as $key => $values){
echo $key." bbbb ".$values;
}
使用迭代器
$it->rewind();
while($it->valid()){
echo $it->key()." ccc ".$it->current()."\n";
$it->next();
}
$it->rewind();
if($it->valid()){
$it->seek(2);
while($it->valid()){
echo $it->key()." ccc ".$it->current()."\n";
$it->next();
}
}
会从第2个元素开始
$it->ksort();
$it->asort();
appenditerator
能陆续遍历几个迭代器
按顺序迭代访问几个不同的迭代器。例如,希望在一次循环中迭代访问两个或者更多的组合
<?php
$array_a = new ArrayIterator(array('a','b','c'));
$array_b = new ArrayIterator(array('w','e','d'));
$array = new AppendIterator();
$array->append($array_a);
$array->append($array_b);
foreach($array as $key => $value){
echo $key." aaaa ".$value."\n";
}
?>
multipleiterator
multipleiterator用于把多个iterator里面的数据组合成为一个整体访问
<?php
$id = new ArrayIterator(array('1','2','3'));
$name = new ArrayIterator(array('王朝阳','啊啊','阿萨'));
$num = new ArrayIterator(array('22','232','2323'));
$multi = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);
$multi->attachIterator($id,"ID");
$multi->attachIterator($name,"NAME");
$multi->attachIterator($num,"NUM");
foreach($multi as $value){
print_r($value);
}
?>
FilesystemIterator
<?php
date_default_timezone_set('PRC');
$it = new FileSystemIterator('.');
foreach ($it as $finfo) {
# code...
echo date("Y-m-d H:i:s",$finfo->getMTime())."\n";
}
?>
<?php
date_default_timezone_set('PRC');
$it = new FileSystemIterator('.');
foreach ($it as $finfo) {
# code...
//echo date("Y-m-d H:i:s",$finfo->getMTime())."\n";
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());
}
?>
2017-06-29 09:14:42 282 appiterator.php
2017-06-29 09:03:28 698 arrayinterator.php
2017-06-29 10:33:32 345 filesystemiterator.php
2017-06-29 09:46:06 404 mutipleiterator.php
2017-06-28 16:38:11 735 spldoublelinkedlist.php
2017-06-28 17:27:32 244 splqueue.php
2017-06-28 17:08:17 737 splstack01.php
4-1SPL接口简介
以概念讲解为主,通过实例讲解countable接口的使用
教学目的
理解countable。outeriterator。recursiveiterator和seekableiterator四个接口的概念
熟练掌握countable的接口
spl的解除接口里面定义了最常用的接口
countable。继承了该接口的类可以直接调用count()得到元素个数
outeriterator。如果想对迭代器进行一定的处理之后再返回,可以用这个接口
recursiveiterator 可以对多层结构的迭代器进行迭代,比如遍历一棵树
seekableiterator 可以通过seek方法定位到几何里面特定元素
countable
在里面经常直接用count($obj)方法获得对象里面的元素的个数
count(array('name'=>'peter'),'id'=>'5');
可以得到结果是2
对于我们自定义的类,也可以这样访问吗?
<?php
class countmy implements Countable{
public $_mycount = 3;
public function count(){
return $this->_mycount;
}
}
$obj = new countmy();
echo count($obj);
?>
outerIterator
如果想对迭代器进行一定的处理之后,再返回,可以用这个接口
IteratorIterator类是outeriterator的实现,扩展的时候可以直接继承IteratorIterator
recursiveiterator
可以对多层结构的迭代器进行迭代,比如遍历一棵树,所具有层次结构特点的数据,都可以用这个接口遍历,如,文件夹
关键方法
hashchild方法用于判断当前结点是否存在子节点
getchild方法用于得到当前子节点的迭代器
recursiveArrayiterator recursiveCachingiterator 等以recursive开头的类都能进行多层次结构化的遍历
5-1基础函数
spl函数的使用autoload
什么是autoload,为了初始化PHP中类对象,需要通过一定的方法寻找到类的定义。通常情况下,定义在一个单独的文件中。
autoload就是PHP找到这些类文件的方法
<?php
//spl_autoload_extensions('.class.php');
//spl_autoload_extensions('.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
class test{
public function __construct(){
echo "loadding";
}
}
?>
<?php
class test{
public function __construct(){
echo "loadding php";
}
}
5-2 使用__autoload装载类
<?php
function __autoload($class_name){
//定义—__autoload函数,可以在不调用spl_autoload_register函数的情况下完成类的装在
echo "__autoload class:".$class_name."\n";
//require_once("libs/".$class_name.'.php');
require_once("libs/".$class_name.'.class.php');//装载类
}
new test();
?>
function classautoloader($class_name){
//定义一个替换__autoload函数的类文件装在函数
echo "classloader".$class_name."\n";
//require_once("libs/".$class_name.'.class.php');
require_once("libs/".$class_name.'.php');
}
spl_autoload_register('classautoloader');
//传入定义好的装在类的函数的名称__autoload函数
new test();
<?php
function classautoloader($class_name){
//定义一个替换__autoload函数的类文件装在函数
echo "classloader".$class_name."\n";
//require_once("libs/".$class_name.'.class.php');
set_include_path("libs/");
spl_autoload($class_name.'.class');
//当我们不用require或require_once载入类文件的时候,而想通过系统查找include_path来装在类时,必须显式调用spl_autoload函数,参数是类的名称来重启类文件的自动查找
}
spl_autoload_register('classautoloader');
//传入定义好的装在类的函数的名称__autoload函数
new test();
?>
6-1spl文件处理类库
SplFileInfo用于获得文件的基本信息,比如修改时间、大小、目录等信息
SplFileObject用于操作文件的内容,比如读取,写入
<?php
date_default_timezone_set('PRC');
$file = new SplFileInfo("ttt.txt");
echo "file is create in ".date("Y-m-d H:i:s",$file->getCTime());
echo "file is modify in ".date("Y-m-d H:i:s",$file->getMTime());
echo "file is size in ".date("Y-m-d H:i:s",$file->getSize());
$fileObj = $file->openFile('r');
while ($fileObj->valid()) {
# code...
echo $fileObj->fgets();
}
$fileObj = null;
$file = null;
?>