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
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);
}
#include "spl_iterators.h"
#include "spl_sxe.h"
#include "spl_exceptions.h"
+#include "spl_observer.h"
#ifdef COMPILE_DL_SPL
ZEND_GET_MODULE(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;
}
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); \
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 */
*
* - 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
*
* - 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>.
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]);
+}
+
?>
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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
+ */
--- /dev/null
+--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===