Skip to content

Observer

Problématique

Comment prévenir un ensemble d’objets lorsqu’un autre objet est modifié?

Observer est l’objet qui souhaite être prévenu du changement d’état d’un autre objet

Observable (Sujet) est un objet capable de prévenir au autre objet lorsqu’il est modifié

Solution

L’objet Observer doit s’enregistrer auprès de l’objet Observable

class Memory implements SplSubject
{
	const READ_OPERATION  = 0 ;
	const WRITE_OPERATION = 1 ;
 
	private $data           = array() ;
	private $observers      = array() ;
	private $last_operation = null ;
	private $address        = null ;
	private $value          = null ;
 
	public function getLastOperation()
	{
		return $this->last_operation ;
	}
 
	public function getAddress()
	{
		return $this->address ;
	}
 
	public function getValue()
	{
		return $this->value ;
	}
 
	public function read($address)
	{
		$this->last_operation = self::READ_OPERATION ;
		$this->address        = $address ;
		$this->value          = isset($this->data[$address]) ? $this->data[$address] : 0 ;
 
		$this->notify() ;
		return $this->value ;
	}
 
	public function write($address, $value)
	{
		$this->last_operation = self::WRITE_OPERATION ;
		$this->address        = $address ;
		$this->value          = $value ;
 
		$this->data[$address] = $value ;
		$this->notify() ;
	}
 
	public function attach(SplObserver $observer)
	{
		if(in_array($observer, $this->observers))
			return ;
 
		$this->observers[] = $observer ;
	}
 
	public function detach(SplObserver $observer)
	{
		$key = array_search($observer, $this->observers) ;
		if(is_null($key))
			return ;
 
		unset($this->observers[$key]) ;
	}
 
	public function notify()
	{
		foreach($this->observers as $obs)
		{
			$obs->update($this) ;
		}
	}
}
 
class MemoryLog implements SplObserver
{
	private $filename = '' ;
 
	public function __construct($filename)
	{
		$this->filename = $filename ;
	}
 
	public function update(SplSubject $subject)
	{
		file_put_contents(
			$this->filename,
			'Last operation: ' . $subject->getLastOperation() .
			' - address: ' . $subject->getAddress() .
			' - value: ' . $subject->getValue() .
			"\r\n",
			FILE_APPEND
		) ;
	}
}
 
class MemoryDisplayEvents implements SplObserver
{
	public function update(SplSubject $subject)
	{
		echo $subject->getLastOperation() == Memory::READ_OPERATION ? 'read' : 'write' ;
		echo ' at ', $subject->getAddress(), ' : ', $subject->getValue(), '<br />' ;
	}
}
 
 
 
$mem = new Memory() ;
$mem->attach(new MemoryLog('C:/mem.log')) ;
$mem->attach(new MemoryDisplayEvents()) ;
 
for($i = 0 ; $i < 50 ; $i++)
{
	$address = rand(0,10) ;
	if(rand() % 2)
	{
		$mem->read($address) ;
	}
	else
	{
		$value = rand(0,255) ;
		$mem->write($address, $value) ;
	}
}