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 MethodImps 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
;
50 $this->imps
[$name] = new internal\
MethodImp($this, $method);
54 /*! Gets the object to which this interface is bound. */
60 /*! Sets whether NULL is allowed. */
61 public function set_null_allowed($flag)
63 $this->null_allowed
= $flag;
66 /*! Binds an object to the interface. */
67 public function Bind($object)
69 $this->_CheckObject($object);
70 $this->object = $object;
71 $this->object_reflector
= new \
ReflectionClass($this->object);
74 /*! Magic method that performs the actual method invocation. */
75 public function __call($meth, $args)
78 if (!$this->null_allowed
)
79 throw new WeakInterfaceException('NULL object when calling ' . $meth);
84 return $this->imps
[$meth]->Invoke($this->object_reflector
, $args);
87 /*! Ensures that the bound object properly implements the interface. */
88 private function _CheckObject($object)
90 $reflector = new \
ReflectionClass($object);
91 $methods = $reflector->GetMethods();
93 foreach ($methods as $method) {
94 $by_name[$method->name
] = $method;
97 foreach ($this->imps
as $name => $imp) {
98 if ($imp->IsRequired() && !isset($by_name[$name]))
99 throw new WeakInterfaceException($reflector->name
. ' does not implement required interface method ' . $name);
101 if (isset($by_name[$name]) && !$imp->Matches($by_name[$name]))
102 throw new WeakInterfaceException($reflector->name
. '::' . $name . ' does not match interface definition');
107 class WeakInterfaceException
extends \Exception
{}
109 } // namespace hoplite\base
111 namespace hoplite
\base\internal
{
114 An encapsulation of a method implementation.
118 /*! @var WeakInterface The interface to which this method belongs. */
119 private $interface = NULL
;
121 /*! @var ReflectionMethod The method of the actual interface that this is implementing. */
122 private $method = NULL
;
124 /*! @var bool Whether or not this is required. */
125 private $required = FALSE
;
127 public function __construct(\hoplite
\base\WeakInterface
$interface,
128 \ReflectionMethod
$method)
130 $this->interface = $interface;
131 $this->method
= $method;
132 $this->required
= strpos($this->method
->GetDocComment(), '@required') !== FALSE
;
135 /*! Forwards a method call. */
136 public function Invoke($reflector, $args)
139 $impl = $reflector->GetMethod($this->method
->name
);
140 } catch (\ReflectionException
$e) {
145 return $impl->InvokeArgs($this->interface->get(), $args);
148 /*! Performs method signature validation. */
149 public function Matches(\ReflectionMethod
$method)
151 return $method->GetParameters() == $this->method
->GetParameters();
154 /*! Checks if a method is marked as required. */
155 public function IsRequired()
157 return $this->required
;
161 } // namespace hoplite\base\internal