迭代器接口描述(接口在C里定义,这只是描述)
interface Iterator { public function current(); public function key(); public function next(); public function rewind(); }
//迭代器辅助函数 function print_entry($iterator) { print($iterator->current()); return true; } $array = array(1,2,3); $iterator = new ArrayIterator($array); iterator_apply($iterator, 'print_entry',array($iterator)); //相当于array_walk
观察者模式
观察者模式:允许某个类观察另外一个类的状态,当被观察的类的状态发生变化时, 这个模式会得到通知
被观察的类叫subject,负责观察的类叫做observer
SPL提供了SplSubject和SplObserver接口
SplSubject 接口 interface SplSubject { public function attach(SplObserver $observer); public function detach(SplObserver $observer); public function notify(); } SplObserver 接口 interface SplObserver { public function update(SplObserver $subject); }
//被观察者 class DemoSubject implements SplSubject { private $observers, $value; public function __construct() { $this->observers = array(); } public function attach(SplObserver $observer) { $this->observers[] = $observer; } public function detach(SplObserver $observer) { if($idx = array_search($observer, $this->observers)) { unset($this->observers[$idx]); } } public function notify() { foreach ($this->observers as $observer) { $observer->update($this); } } public function setValue($value) { $this->value = $value; $this->notify(); } public function getValue() { return $this->value; } } //观察者 class DemoObserver implements SplObserver { public function update(SplSubject $subject) { echo 'The new value is ' . $subject->getValue(); } } $subject = new DemoSubject(); $observer = new DemoObserver(); $subject->attach($observer); $subject->setValue('hello,world');
更好的观察者模式
观察模式的优点在于,挂接到订阅者上的观察者可多可少,并且不需要提前知道哪个类会响应subject类发出的事件
PHP6提供了SplObjectStorage类,这个类提升了观察者模式的可用性.这个类与数组相似,但它只能存储唯一性的对象,而且只存储这些对象的引用.这种做法有几个好处.
现在不能挂接一个类两次,可以防止多交代调用同一个对象的update()方法,而且,不需要迭代访问或者搜索集合,就可以从集合中删除某个对象,这提高了效率
//被观察者 class DemoSubject implements SplSubject { private $observers, $value; public function __construct() { $this->observers = new SplObjectStorage(); } public function attach(SplObserver $observer) { $this->observers->attach($observer); } public function detach(SplObserver $observer) { $this->observers->detach($observer); } public function notify() { foreach($this->observers as $observer) { $this->observers->update($this); } } public function setValue($value) { $this->value = $value; $this->notify(); } public function getValue() { return $this->value; } } //观察者 class DemoObserver implements SplObserver { public function update(SplSubject $subject) { echo 'The new value is ' . $subject->getValue(); } } $subject = new DemoSubject(); $observer = new DemoObserver(); $subject->attach($observer); $subject->attach($observer); $subject->setValue('hello,world');
序列化
SPL的Serializable接口为一些高级的序列化场景提供了支持,非SPL的序列化魔术方法的__sleep和__wakeup有一些问题,这些问题在SPL接口中都得到了解决
魔术方法不能序列化基类的私有变量.实现的__sleep函数必须返回变量名称的一个数组,并且要包含在序列化输出结果中,由于序列化发生的程序中,基类的私有成员的访问受到了限制.
通过允许调用父类的serialize()方法, Serializable接口消除了这一限制,父类的serialize()方法可以返回父类中序列化后的私有成员.
//魔术方法的序列化技术 error_reporting(E_ALL); //显示错误通知 class Base { private $baseVar; public function __construct() { $this->baseVar = 'foo'; } } class Extender extends Base { private $extendVar; public function __construct() { parent::__construct(); $this->extendVar = 'bar'; } public function __sleep() { return array('extenderVar','baseVar'); } } $instance = new Extender(); $serialized = serialize($instance); echo $serialized . ' '; $restored = unserialize($serialized);
序列化对象(包含私有属性)
Serializable接口:
当实现 Serialize()方法,要求返回代表这个对象的序列化以后的字符,这个字符串通常是通过调用 serialize()方法获得的
unserialize()方法允许重新构造对象,它接受序列化的字符串作为输入.
interface Iterator { public function serialize(); public function unserialize($serialized); }
error_reporting(E_ALL); //显示错误通知 class Base implements Serializable { private $baseVar; public function __construct() { $this->baseVar = 'foo'; } public function serialize() { return serialize($this->baseVar); } public function unserialize($serialized) { $this->baseVar = unserialize($serialized); } public function printMe() { echo $this->baseVar . ' '; } } class Extender extends Base { private $extendVar; public function __construct() { parent::__construct(); $this->extendVar = 'bar'; } public function serialize() { $baseSerialized = parent::serialize(); return serialize(array($this->extendVar,$baseSerialized)); } public function unserialize($serialized) { $temp = unserialize($serialized); $this->extendVar = $temp[0]; parent::unserialize($temp[1]); } } $instance = new Extender(); $serialized = serialize($instance); echo $serialized . ' '; $restored = unserialize($serialized); $restored->printMe();
SPL自动加载
安全的类加载方法
if(spl_autoload_call($class_name) && class_exists('className',false)) { echo 'className was loaded'; //安全的实例化className类 $instance = new className; } else { //在这里实例化className类是不安全的 echo 'className was not found'; }
为对象设置一个独一无二的代码
class a{} $instance = new a(); $reference = $instance; echo spl_object_hash($instance) . PHP_EOL; echo spl_object_hash($reference);
IteratorAggregate接口
IteratorAggregate接口是用来将Iterator接口要求实现的5个迭代器方法委托给其他类的.
这让你可以在类的外部实现迭代功能,并允许重新使用常用的迭代器方法,而不是在编写的每个可迭代类中重复使用这些方法
class MyIterableClass implements IteratorAggregate { protected $arr; public function __construct() { $this->arr = array(1,2,3); } public function getIterator() { return new ArrayIterator($this->arr); } } //foreach循环遍历一个类 foreach(new MyIterableClass() as $value) { echo $value . PHP_EOL; }
数组迭代器
数组迭代器实现SQL的LIMIT子句和OFFSET子句相同的迭代访问功能
$arr = array('a','b','c','e','f','g','h','i','j','k'); $arrIterator = new ArrayIterator($arr); $limitIterator = new LimitIterator($arrIterator, 3, 4); foreach($limitIterator as $v) { echo $v; }
在一个循环中抚今追昔访问两个或多个数组
$arrFirst = new ArrayIterator(array(1,2,3)); $arrSecond = new ArrayIterator(array(4,5,6)); $iterator = new AppendIterator(); $iterator->append($arrFirst); $iterator->append($arrSecond); foreach($iterator as $v) { echo $v; }
高级的数组合并功能
使用LimitIterator迭代器,AppendIterator迭代器和iterator_to_array()函数创建一个包含了每个输入数组前两元素的数组
$arrFirst = new ArrayIterator(array(1,2,3)); $arrSecond = new ArrayIterator(array(4,5,6)); $iterator = new AppendIterator(); $iterator->append(new LimitIterator($arrFirst, 0, 2)); $iterator->append(new LimitIterator($arrSecond, 0, 2)); print_r(iterator_to_array($iterator,false));
过滤数组接口FilterIterator
class GreaterThanThreeFilterIterator extends FilterIterator { public function accept() { return ($this->current() > 3); } } $arr = new ArrayIterator(array(1,2,3,4,5,6,7,8)); $iterator = new GreaterThanThreeFilterIterator($arr); print_r(iterator_to_array($iterator));
正则过滤数组接口regexIterator从FilterIterator类继承而来,允许使用几种正则表达式模式来匹配那些键值
$arr = array('apple','avocado','orange','pineapple'); $arrIterator = new ArrayIterator($arr); $iterator = new RegexIterator($arrIterator, '/^a/'); print_r(iterator_to_array($iterator));
递归数组接口RecursiveArrayIterator,RecursiveIteratorIterator
$arr = array( 0 => 'a', 1 => array('a','b','c'), 2 => 'b', 3 => array('a','b','c'), 4 => 'c' ); $arrayIterator = new RecursiveArrayIterator($arr); $it = new RecursiveIteratorIterator($arrayIterator); print_r(iterator_to_array($it,false));
数组重载
ArrayAccess接口:允许使用[]数组语法访问数据
使用ArrayAccess接口使对象的行为看起来和数组一样,包含四个方法
interface Iterator { public function offsetExistsw($offset); public function offsetSet($offset,$value); public function offsetGet($offset); public function offsetUnSet($offset); }
class MyArray implements ArrayAccess { protected $_arr; public function __construct() { $this->_arr = array(); } public function offsetSet($offset, $value) { $this->_arr[$offset] = $value; } public function offsetGet($offset) { return $this->_arr[$offset]; } public function offsetExists($offset) { return array_key_exists($offset, $this->_arr); } public function offsetUnset($offset) { unset($this->_arr[$offset]); } } $myArray = new MyArray(); //创建可作为数组使用的对象 $myArray['first'] = 'test'; //offsetSet,通过键值设置数据 $demo = $myArray['first']; //offsetGet,通过键值获得数据 unset($myArray['first']); //offsetUnset,移除键值
ArrayObject类是一个ArrayAccess接口的实现类,它还提供了迭代功能,以及很多用来排序和处理数据的非常有用的方法
$myArray = new ArrayObject(); $myArray['first'] = 'first'; $myArray['second'] = 'second'; $myArray['third'] = 'third'; $demo = $myArray['first']; unset($myArray['first']); $numElements = count($myArray); foreach($myArray as $key=>$value) { echo $value . PHP_EOL; } var_dump($myArray);