]> granicus.if.org Git - php/commitdiff
- Initial Observer implementation
authorMarcus Boerger <helly@php.net>
Tue, 8 Feb 2005 20:42:48 +0000 (20:42 +0000)
committerMarcus Boerger <helly@php.net>
Tue, 8 Feb 2005 20:42:48 +0000 (20:42 +0000)
ext/spl/config.m4
ext/spl/config.w32
ext/spl/php_spl.c
ext/spl/spl.php
ext/spl/spl_observer.c [new file with mode: 0755]
ext/spl/spl_observer.h [new file with mode: 0755]
ext/spl/tests/observer_001.phpt [new file with mode: 0755]

index 4760a14203722361abe8bc7b3952ce63bd3d1722..eea80921666f0bcd371eeaed0fc6c4537b419c8b 100755 (executable)
@@ -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
index 255a2b4eab5b25f17fac659b47c40e01805880f5..931a6704c770b1451204aa6c2313ea337384e818 100644 (file)
@@ -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);
 }
index 2486f8d3bb10c56b4d3a2cec2dc52346209a7460..d6304635c7ce59216746a28e8d2737e4443bca9f 100755 (executable)
@@ -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 */
index c54c22a21a8ff477fb0fd6eaa4607261231e01c3..49309bdf1146f6312f9900221de2250ba74dd1ba 100755 (executable)
@@ -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
  *
  * - 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]);
+}
+
 ?>
diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c
new file mode 100755 (executable)
index 0000000..9c12eb4
--- /dev/null
@@ -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
+ */
diff --git a/ext/spl/spl_observer.h b/ext/spl/spl_observer.h
new file mode 100755 (executable)
index 0000000..857116e
--- /dev/null
@@ -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
+ */
diff --git a/ext/spl/tests/observer_001.phpt b/ext/spl/tests/observer_001.phpt
new file mode 100755 (executable)
index 0000000..3b20e25
--- /dev/null
@@ -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===