[字号:  ]

Happy Wording With SPL---OOP的好帮手【2008年11月27日基础(下)完】

发布时间:2008-11-26 14:25   作者: 某个人   信息来源: PHPChina 开源社区门户

QUOTE:

本教程版权所有:SamPeng
网址:www.sampeng.cn
谢谢转帖的朋友保留此版权信息
顺便求个广东的工作。
本文假定读者是在OOP环境下进行思考问题。环境PHP,5,2以上
SPL---Standard PHP Library 标准PHP类库
这是个好东西。好像很少人用。任何5.2以上版本的php都已经预装在php内核里面了。效率不是问题。我检测了一下我常用的几个类的效用问题。和函数处理是相当的。为什么有这样好的工具反而很少人用呢。
  他本身是一个大的类库。我的php安装版本只有核心的几个类和接口。
在熟练使用后可以非常大限度的提高自己的工作效率。
  下面是他的类图。非常庞大


interfaceIterator__inherit__graph.png


最好是下载到本地,然后通过浏览软件缩放。
  主要是几个部分:

QUOTE:


terators:迭代器。事实上是各种已经封装好的迭代器模式。方便进行各种操作。
Directories and Files:文件目录操作类库
XML:XML操作类库。在这个版本的SPL里。暂时只有一个简单xml操作类。
Array Overloading:数组操作。事实上这个类别的类库我也没完全搞明白。希望能和大家一起学习进步
Exceptions:异常类。几个异常问题。他是根据逻辑结构划分。如果不想定义自己的异常机制。可以直接用这些。
Observer:观察者模式。这是个好东西。。。我的观察者模式已经完全使用这个接口来操作。详细请看我blog文章:点击进入
还有一个是autoload机制。简单点说就是废掉autoload方法。使用自定义的函数作为autoload。因为同时存在两个autoload是会抛出一个致命错误的。详细内容:点击进入
  本教程主要是讲解Iterators,Directories and Files和Array Overloading。Observer已经在blog中阐述,就不再啰嗦了。异常类主要是一些逻辑。大家可以看api来明白逻辑异常是怎么回事。更多的原因是使用异常机制的会自己定义异常类。用其他的反而会打乱自己的机制。XML太简单了。。意义不大。况且XML也是建立在Directories and Files机制下的。
  下面简单引用API上的列表。点滴列表上的链接。可以查看每个类的结构和内置方法的机理。因为考虑到很多朋友的英文并不好(其实我也是个开着金山词霸的菜鸟),国内这方面的资料很少。所以,写一个深入浅出型的SPL介绍和使用吧。希望能起一个抛砖引玉的作用。他真的很强大。减少大量的工作量。

QUOTE:

1) Iterators SPL offers some advanced iterator algorithms:


2) Directories and Files SPL offers two advanced directory and file handling classes: 3) XML SPL offers an advanced XML handling class: 4) Array Overloading SPL offers advanced Array overloading: As the above suggest an ArrayObject creates an ArrayIterator when it comes to iteration (e.g. ArrayObject instance used inside foreach). 5) Counting
  • interface Countable allows to hook into the standard array function count().
6) Exceptions SPL provides a set of standard Exception classes each meant to indicate a certain problem type. 7) Observer SPL suggests a standard way of implementing the observer pattern.
这只是基本的类。当你知道这些类的作用和使用方法。配合API,可以写出适合自己的自定义的操作类。事实上如果安装包完整,是要包含一个ext/SPL的目录。我很奇怪为什么我的php没有这个目录。所以很麻烦,自定义的类的自己写或者直接在API上面找到已经写好的例子来进行修改。
下面的时间我会每一个部分都进行详细的论述。希望能给大家带来帮助。

[ 本帖最后由 某个人 于 2008-11-27 17:22 编辑 ]

最新回复

某个人 at 2008-11-26 14:27:14
不要看上面图那么复杂。最顶层的Iterator接口是所有SPL迭代的核心接口。他是用C语言代码编写的。由于我不知道怎么调试出C语言的编码结构出来。而API上是已经通过PHP的方式给描绘了的。
  他的实质接口内容,是这个样子的:

QUOTE:


注意:这只是一个形象化的暂时Iterator的php形式。请不要自己去定义这样的接口的。他是php内部自动就定义好了的
看到上面的接口结构。我想如果了解迭代器模式的朋友可能并不觉得模式。这就是一个实现迭代器模式的基本结构。如果不明白迭代器模式。点击查看详细
  大家很喜欢用数组操作。所有的迭代对象都能够跟踪他的初始状态从而进行进一步的迭代。换句话说,迭代对象内部会有一个像数组指针一样的东西。由它来一步一步的追中现有的状态。也就是说,在你的对象中,任何种类的变量都能够跟踪初始状态的元件,这个跟踪能够记录下元件的位置。
  可能这样的文字解释。你无法了解。下面通过图解来说明这个过程。理解这个过程是非常重要的。能够让你清晰的了解你需要如何将你的对象采用一种迭代的方式进行操作。
对于Iterator的各个方法的说明:

QUOTE:

current()  返回一个值,这个值等于当前元件。可以理解成数组索引比如$A.等同于指引了b这个索引现在在数组中的位置。数组索引是固定的。但这个current返回的值一步一步迭代而来的。他就起到了我前面所说的追踪元件的作用,他是记录元件位置的值。
key() 返回当前的元件指针的名称或者索引。我的理解是通过这一个值的递增从而让这个迭代过程开始执行
next() 等同于让一个数组指针前进,进入下一个元素。也就是迭代过程的具体实现。因为我没办法看到源代码。所以我个人的理解是这个方法操作key之递增,current追踪到下一个元件。
rewind()  理解为移动数组指针到起始部分
valid() 判断是否为一个当前元件。在调用这个方法之后,调用next()和rewind()
了解这些方法的作用。可以帮助你在自定义类实现Iterator的时候知道他内部是如何操作的。
简单的介绍了每个方法的作用。下面来看看这个迭代是如何进行的。
用图来说明:


迭代器流程.png


这个图已经很清晰的让我们知道了整个迭代过程了。
了解迭代器模式的时候,我们知道,迭代的核心是循环。我上面讲的流程,就是整个循环是如何实现元件的迭代的。
下面我们将来仔细了解继承他的类和如何使用。
先来了解一下SPL迭代器中的两个工具函数

QUOTE:


Iterator_to_array($iterator):从字面上就能明白这个函数的作用,将一个迭代器换算成数组。他的作用是保存你在迭代操作后的冗长的迭代数据变化为数组。迭代数据可以为任何对象的集合。也就是说。它起到了一个对象到数组的衔接作用。让我们操作对象集群像操作数组一样的方便。
Iterator_count($iterator):返回一个迭代中有多少元素在里面

QUOTE:


注意:如果你的迭代器函数中vaild()返回的是false(也就是说不是当前元素).不要使用这些函数,因为会造成无限死循环

QUOTE:

Iterator_apply($iterator,callback,[user date]):这个方法是让迭代中的每一个函数都执行callback定义的执行函数。等同于array_walk的机制
下面是一个Iterator_apply的应用

输出就是123
看起来并没有什么新奇的地方,事实上他的效果和array_walk的效果是一样的。
但记住,迭代器,是让我们对任何对象都能像数组一样的操作。并不需要知道内部如何操作机制。当然这个例子只是作为说明。
接下来我们需要了解另一个SPL的基础Array Overload
这个机制提供了我们像数组一样访问对象的方法。也就意味着,我们能够在对象集群中使用[]这样的语法,当然,我对这个ArrayOverload的理解并不深入。所以我希望大家能够在接下来的时间里和我一起进步和探讨。写教程一半的原因是希望我也能够在写写教程的过程中吸取到一些思考和经验。
下面让我们看看这个机制主要基础是如何的。他是由几个不同的类去实现。但是都同时是实现了下面这几个接口
ArrayAccess
接口定义如下:

这个接口没什么好说的。到下面具体讲Array Overload的时候再具体描述。这里是先给大家一个大致的概念

QUOTE:

offsetExists 判断一个给定的offset是否在数组中存在(offset不知道是什么意思。偏移量?)
offsetSet 设置一个数据给指定的offset
offsetGet 返回一个数据给指定的offset
offsetUnset 注销也就是unset指定的offset
真正的基础开始了
  SPL提供了5个基础接口:Traversable, Iterator, IteratorAggregate,OuterIterator, 和 RecursiveIterator。我们必须先来了解他们。因为所有SPL定义好的类都是通过实现他们而实现特定的功能。作为开发者,最好的情况是使用程序或者类库提供一定的接口,然后开发出自己的自定义类来完成自己的需求。当然,在一个刚接触的情况下,使用自定义好的类是个不错的选择。SPL提供了过滤器,目录访问等等的内部定义类。后面我会陆续介绍的。但这章的掌握后,可以根据自己的需求开发自定义的类了。
Traversable
  回头看上面的类图。所有的SPL的顶端接口是Traversable接口。他可以让所有实现他的对象能够在foreach对象里面进行循环。但是,这个接口是一个内置接口。只能是PHP内部类才能够实现,通过用户的直接实现将导致抛出一个错误异常。当然,PHP是提供了这个接口的外部类的访问办法。就是通过实现Iterator和IteratorAggregate接口达到目的。这样我们只要实现了这两个接口。就等于Traversable。不要问我为什么。去看OOP接口的说明部分。
  Iterator
  上面的基础中的基础已经讲解了他所有的定义方法和流程,这里就不再赘述。
  作为提醒:他主要有这几个方法:rewind(), current(), key(), next(), and valid().
  IteratorAggregate
先来看看他的结构

  这个接口常被用来使用Iterator的5个方法之用。任何实现这个接口的类。在方法体内必须由一个实现了Iterator的类的对象作为返回值。因为getIterator方法能够将类的信息传递到一个特殊的迭代器类里面。这些数据可能是一个基本的数组,或者任何你想得到的其他数据。只要这些数据能够被我上面所说的5个方面进行循环控制。
  看上面的类图。真正实现iteratorAggregate的类很少。因为使用这个接口。你只需要实现一个接口和他的getIterator方法就能够使你的对象具有可迭代性。
可能这样说无法理解。下面我举个例子。例子是从书上拿来的。我测试无问题。

只需要将$this->arr这个变量转换成迭代器对象。ArrayIterator这个类后面会说的,这里不做过多解释。就可以让整个对象都具有可迭代性。
输出1,2,3.
再此重申。。。例子采用数组作为例子是为了方便说明。并不代表迭代器只能操作数组。后面不再赘述这个说明
这里留个问题。。前面我说过。实现getIterator方法后。这个类的对象就可以作为迭代器对象使用。那是否在后面输出循环迭代的时候可以用Iterator_to_array?如果可以。结果是什么?
谢谢异度水晶补充:

QUOTE:

IteratorAggregate的作用是让迭代操作可对相同对象嵌套
例如  $a = array(1, 2, 3);
foreach(
$a as $v1)
{
    foreach(
$a as $v2)
    {
    }
}

只是用Iterator接口这个两层循环只会执行3次,而实现了IteratorAggregate接口则会执行9次,当然,其实现还要靠内部写的代码
OuterIterator
  从总类图上面可以看出来,这个接口是个继承于Iterator接口的基本接口。实现了他,也等于要实现Iterator中定义的方法。
下面看看这个接口所定义的方法:
interface OuterIterator extends Iterator {
function getInnerIterator();
}
再看一下实现他的类
AppendIterator, CachingIterator, FilterIterator, IteratorIterator, LimitIterator, 和RecursiveIteratorIterator
可能用语言来表示这个接口的作用会显得很干涩和不容易理解。那让我们来看看实现这个接口的类中是如何应用的
AppendIterator

定义这个变量的位置:
.
仔细看了上面的基础Iterator的接口定义应该就能够理解了这两个位置的逻辑。换句话说,AppendIterator->getIterator()将返回这个内部的迭代器ArrayIterator的当前位置。你可以定义任何的返回。也就是说,你可以在这个方法里操作和返回类的内部迭代器的对象,位置或者任何public属性。利用它来跟踪类的内部迭代器中的状态。
比方说在CachingIterator的实现中,getIterator方法就是返回内部迭代器的一个对象,程序如下:

定义这个it变量是在构造函数中:

这个例子就是通过实现OuterIterator中的getIterator()方法来返回内部内的对象
最后一个基本接口:RecursiveIterator
  老规矩。先看看他的定义:
  
  这个接口是被用来设计成可以迭代递归。他能够递归任何有树型结构和等级结构的迭代器。最简单的例子就是目录结构了。在后面讲解目录迭代器的时候会补充说明这个问题
作为递归函数,是无论如何都需要能够确定是否继续还是停止下来并且返回。
  这里,hasChildren方法是判断是否继续迭代。如果迭代器是有Children的,就掉用getChildren()方法。getChildren方法能够返回一个子迭代器的引用回来。
ok。简单介绍了迭代器的5个主要接口。希望大家和我一样对这5个接口有了一定的认识,通过组合不同的接口而实现自己需要的实现。也不是不可能。当然,作为SPL不可能就提供几个接口就完事了。他自身也定义了很多经常使用的公共类和迭代器方便我们使用。
这些。。。明天再讲了。。今天就讲这么多。

[ 本帖最后由 某个人 于 2008-11-27 17:34 编辑 ]
某个人 at 2008-11-26 14:27:48
继续
某个人 at 2008-11-26 14:28:22
继续
某个人 at 2008-11-26 14:28:37
PhpServerPage at 2008-11-26 14:31:26
看这图我要晕,关系这么复杂。。讨厌,
LeoPHP at 2008-11-26 14:41:53
Standard PHP Library (SPL) Functions 需要着重理解一下。
洪家建大侠对SPL有深刻的理解。
某个人 at 2008-11-26 14:43:53
我也是参看基本参考书,就上自己的理解来写这个教程,还是希望大侠来指导我的错误。也想给大家一个抛砖引玉的作用。毕竟好的东西难道没有中文资料就不让人了解?
刚起来。其实从一开始接触SPL的时候就想写这么个东西。无奈总是想偷懒。
现在是吃饭时间。。。等会来完成迭代类的楼层
jiangwb1 at 2008-11-26 16:30:52

QUOTE:

原帖由 LeoPHP 于 2008-11-26 14:41 发表
Standard PHP Library (SPL) Functions 需要着重理解一下。
洪家建大侠对SPL有深刻的理解。
sorry,是洪建家
某个人 at 2008-11-26 16:49:15
呵呵。名字搞错了问题很严重哦。
希望大侠能来指导。。。我也想深入的理解这个类库。。毕竟我也是个OOP的信徒
某个人 at 2008-11-26 16:58:09
写这种笔记真的很累。。。但是巨有感觉。因为每写一部分,很多自己以前没理解透彻的,都有所突破。
生命如蓝 at 2008-11-26 17:01:33
其实挺佩服的。。。冏。。不知道是俺修行不够,还是啥。。对这些总看得糊里糊涂。
sheak at 2008-11-26 17:02:39
虽然看不怎么懂还是收下先  慢慢学习
某个人 at 2008-11-26 17:08:03

QUOTE:

原帖由 生命如蓝 于 2008-11-26 17:01 发表
其实挺佩服的。。。冏。。不知道是俺修行不够,还是啥。。对这些总看得糊里糊涂。
呵呵。时间长了就看得懂了。。我也是看了好几次,加上多应用几次才明白的。
另外,银魂还可以。。。好了。。我又多了一部漫画。
某个人 at 2008-11-26 22:59:16
我天天在家。所以时间比较充裕。看点书什么的。
如果上班了可能就没这么闲了
某个人 at 2008-11-27 12:48:49
起床。吃饭。。。
然后继续。。
想找份工作了
某个人 at 2008-11-27 17:23:31
ok。。基础的5个接口,今天讲完了。希望大家和我多沟通沟通。。。有些地方我只是提了一些我的理解和看法
异度冰晶 at 2008-11-27 17:27:46
IteratorAggregate的作用是让迭代操作可对相同对象嵌套
例如

只是用Iterator接口这个两层循环只会执行3次,而实现了IteratorAggregate接口则会执行9次,当然,其实现还要靠内部写的代码
某个人 at 2008-11-27 17:31:32
关于这个接口。。
API上实现得很少。。。我只能按照我的理解来说了。
他是将实现了IteratorAggregate接口的类转换成迭代器。自动的进行Iterator内的5个方法。不知道我这样理解是不是对的
某个人 at 2008-11-27 17:35:26
资料少还真是个麻烦
异度冰晶 at 2008-11-27 17:43:58

QUOTE:

原帖由 某个人 于 2008-11-27 17:31 发表
关于这个接口。。
API上实现得很少。。。我只能按照我的理解来说了。
他是将实现了IteratorAggregate接口的类转换成迭代器。自动的进行Iterator内的5个方法。不知道我这样理解是不是对的
我的理解是IteratorAggregate继承了Iterator
在每次遍历开始的时候,用getIterator()生成一个临时的迭代指示器(或者说原对象的一个临时副本),这样遍历的时候就不会与其他正在遍历当前对象的迭代器冲突,以满足嵌套遍历的需求。

目前也没深入研究,你可以看看相关的资料http://www.php.net/~helly/php/ext/spl/main.html