3 // Copyright (c) 2011 Blue Static
5 // This program is free software: you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or any later version.
9 // This program is distributed in the hope that it will be useful, but WITHOUT
10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 // You should have received a copy of the GNU General Public License along with
15 // this program. If not, see <http://www.gnu.org/licenses/>.
17 namespace hoplite
\base
;
20 A WeakInterface is a class that implements some interface and then can bind
21 a subset of those methods to some other object. This allows a delegate pattern
22 to be implemented more easily in that the delegate class need not implement
25 To use this class, define an interface as you normally would. When making a
26 call to an object that implements the interface, create a WeakInterface object
27 and instead make the calls on that.
31 /*! @var array Map of method imps hashes, keyed by the method name. */
32 private $imps = array();
34 /*! @var object The object to which this interface is bound. */
35 private $object = NULL
;
37 /*! @var ReflectionClass The reflector of #object. */
38 private $object_reflector = NULL
;
40 /*! @var bool Whether or not a NULL object will throw when called. */
41 private $null_allowed = TRUE
;
43 /*! Creates a weak interface with the name of an actual interface. */
44 public function __construct($interface)
46 $reflector = new \
ReflectionClass($interface);
47 $methods = $reflector->GetMethods();
48 foreach ($methods as $method) {
49 $name = $method->name
;
52 'required' => strpos($method->GetDocComment(), '@required') !== FALSE
,
54 $this->imps
[$name] = $imp;
58 /*! Gets the object to which this interface is bound. */
64 /*! Sets whether NULL is allowed. */
65 public function set_null_allowed($flag)
67 $this->null_allowed
= $flag;
70 /*! Binds an object to the interface. */
71 public function Bind($object)
73 $this->_CheckObject($object);
74 $this->object = $object;
75 $this->object_reflector
= new \
ReflectionClass($this->object);
78 /*! Magic method that performs the actual method invocation. */
79 public function __call($meth, $args)
82 if (!$this->null_allowed
)
83 throw new WeakInterfaceException('NULL object when calling ' . $meth);
89 $imp = $this->object_reflector
->GetMethod($meth);
90 } catch (\ReflectionException
$e) {
91 if ($this->imps
[$meth]['required'])
95 return $imp->InvokeArgs($this->object, $args);
98 /*! Ensures that the bound object properly implements the interface. */
99 private function _CheckObject($object)
101 $reflector = new \
ReflectionClass($object);
102 $methods = $reflector->GetMethods();
104 foreach ($methods as $method) {
105 $by_name[$method->name
] = $method;
108 foreach ($this->imps
as $name => $imp) {
109 if ($imp['required'] && !isset($by_name[$name]))
110 throw new WeakInterfaceException($reflector->name
. ' does not implement required interface method ' . $name);
112 if (isset($by_name[$name]) && $imp['method']->GetParameters() != $by_name[$name]->GetParameters())
113 throw new WeakInterfaceException($reflector->name
. '::' . $name . ' does not match interface definition');
118 class WeakInterfaceException
extends \Exception
{}