Overview

Packages

  • Injector

Classes

  • Horde_Injector
  • Horde_Injector_Binder_AnnotatedSetters
  • Horde_Injector_Binder_Closure
  • Horde_Injector_Binder_Factory
  • Horde_Injector_Binder_Implementation
  • Horde_Injector_DependencyFinder
  • Horde_Injector_Exception
  • Horde_Injector_TopLevel

Interfaces

  • Horde_Injector_Binder
  • Horde_Injector_Scope
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Injector class for injecting dependencies of objects
  4:  *
  5:  * This class is responsible for injecting dependencies of objects.  It is
  6:  * inspired by the bucket_Container's concept of child scopes, but written to
  7:  * support many different types of bindings as well as allowing for setter
  8:  * injection bindings.
  9:  *
 10:  * @author   Bob Mckee <bmckee@bywires.com>
 11:  * @author   James Pepin <james@jamespepin.com>
 12:  * @category Horde
 13:  * @package  Injector
 14:  */
 15: class Horde_Injector implements Horde_Injector_Scope
 16: {
 17:     /**
 18:      * @var Horde_Injector_Scope
 19:      */
 20:     private $_parentInjector;
 21: 
 22:     /**
 23:      * @var array
 24:      */
 25:     private $_bindings = array();
 26: 
 27:     /**
 28:      * @var array
 29:      */
 30:     private $_instances;
 31: 
 32:     /**
 33:      * Create a new injector object.
 34:      *
 35:      * Every injector object has a parent scope.  For the very first
 36:      * Horde_Injector, you should pass it a Horde_Injector_TopLevel object.
 37:      *
 38:      * @param Horde_Injector_Scope $injector  The parent scope.
 39:      */
 40:     public function __construct(Horde_Injector_Scope $injector)
 41:     {
 42:         $this->_parentInjector = $injector;
 43:         $this->_instances = array(__CLASS__ => $this);
 44:     }
 45: 
 46:     /**
 47:      * Create a child injector that inherits this injector's scope.
 48:      *
 49:      * All child injectors inherit the parent scope.  Any objects that were
 50:      * created using getInstance, will be available to the child container.
 51:      * The child container can set bindings to override the parent, and none
 52:      * of those bindings will leak to the parent.
 53:      *
 54:      * @return Horde_Injector  A child injector with $this as its parent.
 55:      */
 56:     public function createChildInjector()
 57:     {
 58:         return new self($this);
 59:     }
 60: 
 61:     /**
 62:      * Method overloader.  Handles $this->bind[BinderType] type calls.
 63:      *
 64:      * @return Horde_Injector_Binder  See _bind().
 65:      * @throws BadMethodCallException
 66:      */
 67:     public function __call($name, $args)
 68:     {
 69:         if (substr($name, 0, 4) == 'bind') {
 70:             return $this->_bind(substr($name, 4), $args);
 71:         }
 72: 
 73:         throw new BadMethodCallException('Call to undefined method ' . __CLASS__ . '::' . $name . '()');
 74:     }
 75: 
 76:     /**
 77:      * Method that creates binders to send to addBinder(). This is called by
 78:      * the magic method __call() whenever a function is called that starts
 79:      * with bind.
 80:      *
 81:      * @param string $type  The type of Horde_Injector_Binder_ to be created.
 82:      *                      Matches /^Horde_Injector_Binder_(\w+)$/.
 83:      * @param array $args   The constructor arguments for the binder object.
 84:      *
 85:      * @return Horde_Injector_Binder  The binder object created. Useful for
 86:      *                                method chaining.
 87:      * @throws BadMethodCallException
 88:      */
 89:     private function _bind($type, $args)
 90:     {
 91:         $interface = array_shift($args);
 92: 
 93:         if (!$interface) {
 94:             throw new BadMethodCallException('First parameter for "bind' . $type . '" must be the name of an interface or class');
 95:         }
 96: 
 97:         $reflectionClass = new ReflectionClass('Horde_Injector_Binder_' . $type);
 98: 
 99:         $this->_addBinder(
100:             $interface,
101:             $reflectionClass->getConstructor()
102:                 ? $reflectionClass->newInstanceArgs($args)
103:                 : $reflectionClass->newInstance()
104:         );
105: 
106:         return $this->_getBinder($interface);
107:     }
108: 
109:     /**
110:      * Add a Horde_Injector_Binder to an interface
111:      *
112:      * This is the method by which we bind an interface to a concrete
113:      * implentation or factory.  For convenience, binders may be added by
114:      * $this->bind[BinderType].
115:      *
116:      * bindFactory - Creates a Horde_Injector_Binder_Factory
117:      * bindImplementation - Creates a Horde_Injector_Binder_Implementation
118:      *
119:      * All subsequent arguments are passed to the constructor of the
120:      * Horde_Injector_Binder object.
121:      *
122:      * @param string $interface              The interface to bind to.
123:      * @param Horde_Injector_Binder $binder  The binder to be bound to the
124:      *                                       specified $interface.
125:      *
126:      * @return Horde_Injector  A reference to itself for method chaining.
127:      */
128:     public function addBinder($interface, Horde_Injector_Binder $binder)
129:     {
130:         $this->_addBinder($interface, $binder);
131:         return $this;
132:     }
133: 
134:     /**
135:      * @see self::addBinder()
136:      */
137:     private function _addBinder($interface, Horde_Injector_Binder $binder)
138:     {
139:         // First we check to see if our parent already has an equal binder set.
140:         // if so we don't need to do anything
141:         if (!$binder->equals($this->_parentInjector->getBinder($interface))) {
142:             $this->_bindings[$interface] = $binder;
143:         }
144:     }
145: 
146:     /**
147:      * Get the Binder associated with the specified instance.
148:      *
149:      * Binders are objects responsible for binding a particular interface
150:      * with a class. If no binding is set for this object, the parent scope is
151:      * consulted.
152:      *
153:      * @param string $interface  The interface to retrieve binding information
154:      *                           for.
155:      *
156:      * @return Horde_Injector_Binder  The binding set for the specified
157:      *                                interface.
158:      */
159:     public function getBinder($interface)
160:     {
161:         return isset($this->_bindings[$interface])
162:             ? $this->_bindings[$interface]
163:             : $this->_parentInjector->getBinder($interface);
164:     }
165: 
166:     /**
167:      * Get the Binder associated with the specified instance.
168:      *
169:      * @param string $interface  The interface to retrieve binding information
170:      *                           for.
171:      *
172:      * @return Horde_Injector_Binder  The binder object created. Useful for
173:      *                                method chaining.
174:      */
175:     private function _getBinder($interface)
176:     {
177:         return $this->_bindings[$interface];
178:     }
179: 
180:     /**
181:      * Set the object instance to be retrieved by getInstance the next time
182:      * the specified interface is requested.
183:      *
184:      * This method allows you to set the cached object instance so that all
185:      * subsequent getInstance() calls return the object you have specified.
186:      *
187:      * @param string $interface  The interface to bind the instance to.
188:      * @param mixed $instance    The object instance to be bound to the
189:      *                           specified instance.
190:      *
191:      * @return Horde_Injector  A reference to itself for method chaining.
192:      */
193:     public function setInstance($interface, $instance)
194:     {
195:         $this->_instances[$interface] = $instance;
196:         return $this;
197:     }
198: 
199:     /**
200:      * Create a new instance of the specified object/interface.
201:      *
202:      * This method creates a new instance of the specified object/interface.
203:      * NOTE: it does not save that instance for later retrieval. If your
204:      * object should be re-used elsewhere, you should be using getInstance().
205:      *
206:      * @param string $interface  The interface name, or object class to be
207:      *                           created.
208:      *
209:      * @return mixed  A new object that implements $interface.
210:      */
211:     public function createInstance($interface)
212:     {
213:         return $this->getBinder($interface)->create($this);
214:     }
215: 
216:     /**
217:      * Retrieve an instance of the specified object/interface.
218:      *
219:      * This method gets you an instance, and saves a reference to that
220:      * instance for later requests.
221:      *
222:      * Interfaces must be bound to a concrete class to be created this way.
223:      * Concrete instances may be created through reflection.
224:      *
225:      * It does not gaurantee that it is a new instance of the object.  For a
226:      * new instance see createInstance().
227:      *
228:      * @param string $interface  The interface name, or object class to be
229:      *                           created.
230:      *
231:      * @return mixed  An object that implements $interface, but not
232:      *                necessarily a new one.
233:      */
234:     public function getInstance($interface)
235:     {
236:         // Do we have an instance?
237:         if (!$this->hasInstance($interface)) {
238:             // Do we have a binding for this interface? If so then we don't
239:             // ask our parent
240:             if (!isset($this->_bindings[$interface])) {
241:                 // Does our parent have an instance?
242:                 if ($instance = $this->_parentInjector->getInstance($interface)) {
243:                     return $instance;
244:                 }
245:             }
246: 
247:             // We have to make our own instance
248:             $this->setInstance($interface, $this->createInstance($interface));
249:         }
250: 
251:         return $this->_instances[$interface];
252:     }
253: 
254:     /**
255:      * Has the interface for the specified object/interface been created yet?
256:      *
257:      * @param string $interface  The interface name or object class.
258:      *
259:      * @return boolean  True if the instance already has been created.
260:      */
261:     public function hasInstance($interface)
262:     {
263:         return isset($this->_instances[$interface]);
264:     }
265: 
266: }
267: 
API documentation generated by ApiGen