Browse Source

- Initial Observer implementation

PHP-5.1
Marcus Boerger 22 years ago
parent
commit
3fb1c65a41
  1. 2
      ext/spl/config.m4
  2. 2
      ext/spl/config.w32
  3. 4
      ext/spl/php_spl.c
  4. 50
      ext/spl/spl.php
  5. 88
      ext/spl/spl_observer.c
  6. 41
      ext/spl/spl_observer.h
  7. 116
      ext/spl/tests/observer_001.phpt

2
ext/spl/config.m4

@ -9,6 +9,6 @@ if test "$PHP_SPL" != "no"; then
AC_MSG_ERROR(Cannot build SPL as a shared module)
fi
AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard PHP Library) support])
PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c, $ext_shared)
PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c, $ext_shared)
PHP_ADD_EXTENSION_DEP(spl, simplexml)
fi

2
ext/spl/config.w32

@ -7,6 +7,6 @@ if (PHP_SPL != "no") {
if (PHP_SPL_SHARED) {
ERROR("SPL cannot be compiled as a shared ext");
}
EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c");
EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c");
AC_DEFINE('HAVE_SPL', 1);
}

4
ext/spl/php_spl.c

@ -33,6 +33,7 @@
#include "spl_iterators.h"
#include "spl_sxe.h"
#include "spl_exceptions.h"
#include "spl_observer.h"
#ifdef COMPILE_DL_SPL
ZEND_GET_MODULE(spl)
@ -95,6 +96,7 @@ PHP_MINIT_FUNCTION(spl)
PHP_MINIT(spl_directory)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_sxe)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_exceptions)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU);
return SUCCESS;
}
@ -181,6 +183,7 @@ PHP_FUNCTION(class_implements)
SPL_ADD_CLASS(LimitIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(LogicException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(NoRewindIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(Observer, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(OuterIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(OutOfRangeException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(OutOfBoundsException, z_list, sub, allow, ce_flags); \
@ -193,6 +196,7 @@ PHP_FUNCTION(class_implements)
SPL_ADD_CLASS(RuntimeException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SeekableIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SimpleXMLIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(Subject, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \
/* {{{ spl_classes */

50
ext/spl/spl.php

@ -66,6 +66,9 @@
*
* - class ArrayObject implements IteratorAggregate
* - class ArrayIterator implements Iterator
*
* As the above suggest an ArrayObject creates an ArrayIterator when it comes to
* iteration (e.g. ArrayObject instance used inside foreach).
*
* 5) Counting
*
@ -88,9 +91,13 @@
* - class OverflowException extends RuntimeException
* - class RangeException extends RuntimeException
* - class UnderflowException extends RuntimeException
*
* As the above suggest an ArrayObject creates an ArrayIterator when it comes to
* iteration (e.g. ArrayObject instance used inside foreach).
*
* 7) Observer
*
* SPL suggests a standard way of implementing the observer pattern.
*
* - interface Observer
* - interface Subject
*
* A nice article about SPL can be found
* <a href="http://www.sitepoint.com/article/php5-standard-library/1">here</a>.
@ -657,4 +664,41 @@ class SimpleXMLIterator extends SimpleXMLElement implements RecursiveIterator
function getChildren();
}
/** @ingroup SPL
* @brief observer of the observer pattern
*
* For a detailed explanation see Observer pattern in
* <em>
* Gamma, Helm, Johnson, Vlissides<br />
* Design Patterns
* </em>
*/
interface Observer
{
/** Called from the subject (i.e. when it's value has changed).
* @param $subject the callee
*/
function update(Subject $subject);
}
/** @ingroup SPL
* @brief ubject to the observer pattern
* @see Observer
*/
interface Subject
{
/** @param $observer new observer to attach
*/
function attach(Observer $observer);
/** @param $observer existing observer to detach
* @note a non attached observer shouldn't result in a warning or similar
*/
function detach(Observer $observer);
/** @param $ignore optional observer that should not be notified
*/
function notify([Observer $ignore = NULL]);
}
?>

88
ext/spl/spl_observer.c

@ -0,0 +1,88 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2004 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Marcus Boerger <helly@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "zend_interfaces.h"
#include "zend_exceptions.h"
#include "php_spl.h"
#include "spl_functions.h"
#include "spl_engine.h"
#include "spl_observer.h"
SPL_METHOD(Observer, update);
SPL_METHOD(Subject, attach);
SPL_METHOD(Subject, detach);
SPL_METHOD(Subject, notify);
static
ZEND_BEGIN_ARG_INFO(arginfo_Observer_update, 0)
ZEND_ARG_OBJ_INFO(0, subject, Subject, 0)
ZEND_END_ARG_INFO();
static zend_function_entry spl_funcs_Observer[] = {
SPL_ABSTRACT_ME(Observer, update, arginfo_Observer_update)
{NULL, NULL, NULL}
};
static
ZEND_BEGIN_ARG_INFO(arginfo_Subject_attach, 0)
ZEND_ARG_OBJ_INFO(0, observer, Observer, 0)
ZEND_END_ARG_INFO();
/*static
ZEND_BEGIN_ARG_INFO_EX(arginfo_Subject_notify, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, ignore, Observer, 1)
ZEND_END_ARG_INFO();*/
static zend_function_entry spl_funcs_Subject[] = {
SPL_ABSTRACT_ME(Subject, attach, arginfo_Subject_attach)
SPL_ABSTRACT_ME(Subject, detach, arginfo_Subject_attach)
SPL_ABSTRACT_ME(Subject, notify, NULL)
{NULL, NULL, NULL}
};
PHPAPI zend_class_entry *spl_ce_Observer;
PHPAPI zend_class_entry *spl_ce_Subject;
/* {{{ PHP_MINIT_FUNCTION(spl_observer) */
PHP_MINIT_FUNCTION(spl_observer)
{
REGISTER_SPL_INTERFACE(Observer);
REGISTER_SPL_INTERFACE(Subject);
return SUCCESS;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: fdm=marker
* vim: noet sw=4 ts=4
*/

41
ext/spl/spl_observer.h

@ -0,0 +1,41 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2004 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Marcus Boerger <helly@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef SPL_OBSERVER_H
#define SPL_OBSERVER_H
#include "php.h"
#include "php_spl.h"
extern PHPAPI zend_class_entry *spl_ce_Observer;
extern PHPAPI zend_class_entry *spl_ce_Subject;
PHP_MINIT_FUNCTION(spl_observer);
#endif /* SPL_OBSERVER_H */
/*
* Local Variables:
* c-basic-offset: 4
* tab-width: 4
* End:
* vim600: fdm=marker
* vim: noet sw=4 ts=4
*/

116
ext/spl/tests/observer_001.phpt

@ -0,0 +1,116 @@
--TEST--
SPL: Observer and Subject (empty notify)
--FILE--
<?php
class ObserverImpl implements Observer
{
protected $name = '';
function __construct($name = 'obj')
{
$this->name = '$' . $name;
}
function update(Subject $subject)
{
echo $this->name . '->' . __METHOD__ . '(' . $subject->getName() . ");\n";
}
function getName()
{
return $this->name;
}
}
class SubjectImpl implements Subject
{
protected $name = '';
protected $observers = array();
function __construct($name = 'sub')
{
$this->name = '$' . $name;
}
function attach(Observer $observer)
{
echo '$sub->' . __METHOD__ . '(' . $observer->getName() . ");\n";
if (!in_array($observer, $this->observers))
{
$this->observers[] = $observer;
}
}
function detach(Observer $observer)
{
echo '$sub->' . __METHOD__ . '(' . $observer->getName() . ");\n";
$idx = array_search($observer, $this->observers);
if ($idx !== false)
{
unset($this->observers[$idx]);
}
}
function notify()
{
echo '$sub->' . __METHOD__ . "();\n";
foreach($this->observers as $observer)
{
$observer->update($this);
}
}
function getName()
{
return $this->name;
}
}
$sub = new SubjectImpl;
$ob1 = new ObserverImpl("ob1");
$ob2 = new ObserverImpl("ob2");
$ob3 = new ObserverImpl("ob3");
$sub->attach($ob1);
$sub->attach($ob1);
$sub->attach($ob2);
$sub->attach($ob3);
$sub->notify();
$sub->detach($ob3);
$sub->notify();
$sub->detach($ob2);
$sub->detach($ob1);
$sub->notify();
$sub->attach($ob3);
$sub->notify();
?>
===DONE===
--EXPECT--
$sub->SubjectImpl::attach($ob1);
$sub->SubjectImpl::attach($ob1);
$sub->SubjectImpl::attach($ob2);
$sub->SubjectImpl::attach($ob3);
$sub->SubjectImpl::notify();
$ob1->ObserverImpl::update($sub);
$ob2->ObserverImpl::update($sub);
$ob3->ObserverImpl::update($sub);
$sub->SubjectImpl::detach($ob3);
$sub->SubjectImpl::notify();
$ob1->ObserverImpl::update($sub);
$ob2->ObserverImpl::update($sub);
$sub->SubjectImpl::detach($ob2);
$sub->SubjectImpl::detach($ob1);
$sub->SubjectImpl::notify();
$sub->SubjectImpl::attach($ob3);
$sub->SubjectImpl::notify();
$ob3->ObserverImpl::update($sub);
===DONE===
Loading…
Cancel
Save