1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19:
20: class Context extends FreezableObject implements IContext
21: {
22:
23: private $registry = array();
24:
25:
26: private $factories = array();
27:
28:
29:
30: 31: 32: 33: 34: 35: 36: 37:
38: public function addService($name, $service, $singleton = TRUE, array $options = NULL)
39: {
40: $this->updating();
41: if (!is_string($name) || $name === '') {
42: throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
43: }
44:
45: $lower = strtolower($name);
46: if (isset($this->registry[$lower])) { 47: throw new AmbiguousServiceException("Service named '$name' has already been registered.");
48: }
49:
50: if (is_object($service) && !($service instanceof Closure || $service instanceof Callback)) {
51: if (!$singleton || $options) {
52: throw new InvalidArgumentException("Service named '$name' is an instantiated object and must therefore be singleton without options.");
53: }
54: $this->registry[$lower] = $service;
55:
56: } else {
57: if (!$service) {
58: throw new InvalidArgumentException("Service named '$name' is empty.");
59: }
60: $this->factories[$lower] = array($service, $singleton, $options);
61: }
62: }
63:
64:
65:
66: 67: 68: 69:
70: public function removeService($name)
71: {
72: $this->updating();
73: if (!is_string($name) || $name === '') {
74: throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
75: }
76:
77: $lower = strtolower($name);
78: unset($this->registry[$lower], $this->factories[$lower]);
79: }
80:
81:
82:
83: 84: 85: 86: 87: 88:
89: public function getService($name, array $options = NULL)
90: {
91: if (!is_string($name) || $name === '') {
92: throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
93: }
94:
95: $lower = strtolower($name);
96:
97: if (isset($this->registry[$lower])) { 98: if ($options) {
99: throw new InvalidArgumentException("Service named '$name' is singleton and therefore can not have options.");
100: }
101: return $this->registry[$lower];
102:
103: } elseif (isset($this->factories[$lower])) {
104: list($factory, $singleton, $defOptions) = $this->factories[$lower];
105:
106: if ($singleton && $options) {
107: throw new InvalidArgumentException("Service named '$name' is singleton and therefore can not have options.");
108:
109: } elseif ($defOptions) {
110: $options = $options ? $options + $defOptions : $defOptions;
111: }
112:
113: if (is_string($factory) && strpos($factory, ':') === FALSE) { 114: if ($a = strrpos($factory, '\\')) $factory = substr($factory, $a + 1); 115: if (!class_exists($factory)) {
116: throw new AmbiguousServiceException("Cannot instantiate service '$name', class '$factory' not found.");
117: }
118: $service = new $factory;
119: if ($options && method_exists($service, 'setOptions')) {
120: $service->setOptions($options); 121: }
122:
123: } else { 124: $factory = callback($factory);
125: if (!$factory->isCallable()) {
126: throw new InvalidStateException("Cannot instantiate service '$name', handler '$factory' is not callable.");
127: }
128: $service = $factory->invoke($options);
129: if (!is_object($service)) {
130: throw new AmbiguousServiceException("Cannot instantiate service '$name', value returned by '$factory' is not object.");
131: }
132: }
133:
134: if ($singleton) {
135: $this->registry[$lower] = $service;
136: unset($this->factories[$lower]);
137: }
138: return $service;
139:
140: } else {
141: throw new InvalidStateException("Service '$name' not found.");
142: }
143: }
144:
145:
146:
147: 148: 149: 150: 151: 152:
153: public function hasService($name, $created = FALSE)
154: {
155: if (!is_string($name) || $name === '') {
156: throw new InvalidArgumentException("Service name must be a non-empty string, " . gettype($name) . " given.");
157: }
158:
159: $lower = strtolower($name);
160: return isset($this->registry[$lower]) || (!$created && isset($this->factories[$lower]));
161: }
162:
163: }
164:
165:
166:
167: 168: 169: 170: 171:
172: class AmbiguousServiceException extends Exception
173: {
174: }
175: