SPL接口学习总结

迭代器接口描述(接口在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);