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 bool Whether or not a NULL object will throw when called. */
38 private $null_allowed = FALSE
;
40 /*! Creates a weak interface with the name of an actual interface. */
41 public function __construct($interface)
43 $reflector = new \
ReflectionClass($interface);
44 $methods = $reflector->GetMethods();
45 foreach ($methods as $method) {
46 $name = $method->name
;
47 $this->imps
[$name] = new internal\
MethodImp($this, $method);
51 /*! Gets the object to which this interface is bound. */
57 /*! Sets whether NULL is allowed. */
58 public function set_null_allowed($flag)
60 $this->null_allowed
= $flag;
63 /*! Binds an object to the interface. */
64 public function Bind($object)
66 $this->_CheckObject($object);
67 $this->object = $object;
70 /*! Magic method that performs the actual method invocation. */
71 public function __call($meth, $args)
74 if (!$this->null_allowed
)
75 throw new WeakInterfaceException('NULL object when calling ' . $meth);
80 return $this->imps
[$meth]->Invoke($args);
83 /*! Ensures that the bound object properly implements the interface. */
84 private function _CheckObject($object)
86 $reflector = new \
ReflectionClass($object);
87 $methods = $reflector->GetMethods();
89 foreach ($methods as $method) {
90 $by_name[$method->name
] = $method;
93 foreach ($this->imps
as $name => $imp) {
94 if ($imp->IsRequired() && !isset($by_name[$name]))
95 throw new WeakInterfaceException($reflector->name
. ' does not implement required interface method ' . $name);
97 if (isset($by_name[$name]) && !$imp->Matches($by_name[$name]))
98 throw new WeakInterfaceException($reflector->name
. '::' . $name . ' does not match interface definition');
103 class WeakInterfaceException
extends \Exception
{}
105 } // namespace hoplite\base
107 namespace hoplite
\base\internal
{
110 An encapsulation of a method implementation.
114 /*! @var WeakInterface The interface to which this method belongs. */
115 private $interface = NULL
;
117 /*! @var ReflectionMethod The method of the actual interface that this is implementing. */
118 private $method = NULL
;
120 public function __construct(\hoplite
\base\WeakInterface
$interface,
121 \ReflectionMethod
$method)
123 $this->interface = $interface;
124 $this->method
= $method;
127 /*! Forwards a method call. */
128 public function Invoke($args)
130 $reflector = new \
ReflectionClass($this->interface->get());
132 $impl = $reflector->GetMethod($this->method
->name
);
133 } catch (\ReflectionException
$e) {
134 if ($this->IsRequired())
138 return $impl->InvokeArgs($this->interface->get(), $args);
141 /*! Performs method signature validation. */
142 public function Matches(\ReflectionMethod
$method)
144 return $method->GetParameters() == $this->method
->GetParameters();
147 /*! Checks if a method is marked as required. */
148 public function IsRequired()
150 return strpos($this->method
->GetDocComment(), '@required') !== FALSE
;
154 } // namespace hoplite\base\internal