Complex classes like Container often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Container, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 16 | class Container implements ContainerInterface |
||
| 17 | { |
||
| 18 | /** |
||
| 19 | * @var \League\Container\Definition\DefinitionFactoryInterface |
||
| 20 | */ |
||
| 21 | protected $definitionFactory; |
||
| 22 | |||
| 23 | /** |
||
| 24 | * @var \League\Container\Definition\DefinitionInterface[] |
||
| 25 | */ |
||
| 26 | protected $definitions = []; |
||
| 27 | |||
| 28 | /** |
||
| 29 | * @var \League\Container\Definition\DefinitionInterface[] |
||
| 30 | */ |
||
| 31 | protected $sharedDefinitions = []; |
||
| 32 | |||
| 33 | /** |
||
| 34 | * @var \League\Container\Inflector\InflectorAggregateInterface |
||
| 35 | */ |
||
| 36 | protected $inflectors; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * @var \League\Container\ServiceProvider\ServiceProviderAggregateInterface |
||
| 40 | */ |
||
| 41 | protected $providers; |
||
| 42 | |||
| 43 | /** |
||
| 44 | * @var array |
||
| 45 | */ |
||
| 46 | protected $shared = []; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * @var \Interop\Container\ContainerInterface[] |
||
| 50 | */ |
||
| 51 | protected $delegates = []; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * @var bool |
||
| 55 | */ |
||
| 56 | protected $isProtected = false; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * Constructor. |
||
| 60 | * |
||
| 61 | * @param \League\Container\ServiceProvider\ServiceProviderAggregateInterface|null $providers |
||
| 62 | * @param \League\Container\Inflector\InflectorAggregateInterface|null $inflectors |
||
| 63 | * @param \League\Container\Definition\DefinitionFactoryInterface|null $definitionFactory |
||
| 64 | */ |
||
| 65 | 51 | public function __construct( |
|
| 66 | ServiceProviderAggregateInterface $providers = null, |
||
| 67 | InflectorAggregateInterface $inflectors = null, |
||
| 68 | DefinitionFactoryInterface $definitionFactory = null |
||
| 69 | ) { |
||
| 70 | // set required dependencies |
||
| 71 | 51 | $this->providers = (is_null($providers)) |
|
| 72 | 51 | ? (new ServiceProviderAggregate)->setContainer($this) |
|
| 73 | 51 | : $providers->setContainer($this); |
|
| 74 | |||
| 75 | 51 | $this->inflectors = (is_null($inflectors)) |
|
| 76 | 51 | ? (new InflectorAggregate)->setContainer($this) |
|
| 77 | 51 | : $inflectors->setContainer($this); |
|
| 78 | |||
| 79 | 51 | $this->definitionFactory = (is_null($definitionFactory)) |
|
| 80 | 51 | ? (new DefinitionFactory)->setContainer($this) |
|
| 81 | 51 | : $definitionFactory->setContainer($this); |
|
| 82 | 51 | } |
|
| 83 | |||
| 84 | /** |
||
| 85 | * {@inheritdoc} |
||
| 86 | */ |
||
| 87 | 33 | public function get($alias, array $args = []) |
|
| 88 | { |
||
| 89 | 33 | $service = $this->getFromThisContainer($alias, $args); |
|
| 90 | |||
| 91 | 33 | if ($service === false && $this->providers->provides($alias)) { |
|
| 92 | 12 | $this->providers->register($alias); |
|
| 93 | 12 | $service = $this->getFromThisContainer($alias, $args); |
|
| 94 | 12 | } |
|
| 95 | |||
| 96 | 33 | if ($service !== false) { |
|
| 97 | 27 | return $service; |
|
| 98 | } |
||
| 99 | |||
| 100 | 12 | if ($resolved = $this->getFromDelegate($alias, $args)) { |
|
| 101 | 6 | return $this->inflectors->inflect($resolved); |
|
| 102 | } |
||
| 103 | |||
| 104 | 6 | throw new NotFoundException( |
|
| 105 | 6 | sprintf('Alias (%s) is not being managed by the container', $alias) |
|
| 106 | 6 | ); |
|
| 107 | } |
||
| 108 | |||
| 109 | /** |
||
| 110 | * {@inheritdoc} |
||
| 111 | */ |
||
| 112 | 21 | public function has($alias) |
|
| 113 | { |
||
| 114 | 21 | if (array_key_exists($alias, $this->definitions) || $this->hasShared($alias)) { |
|
| 115 | 15 | return true; |
|
| 116 | } |
||
| 117 | |||
| 118 | 9 | if ($this->providers->provides($alias)) { |
|
| 119 | 3 | return true; |
|
| 120 | } |
||
| 121 | |||
| 122 | 9 | return $this->hasInDelegate($alias); |
|
| 123 | } |
||
| 124 | |||
| 125 | /** |
||
| 126 | * Returns a boolean to determine if the container has a shared instance of an alias. |
||
| 127 | * |
||
| 128 | * @param string $alias |
||
| 129 | * @param boolean $resolved |
||
| 130 | * @return boolean |
||
| 131 | */ |
||
| 132 | 42 | public function hasShared($alias, $resolved = false) |
|
| 133 | { |
||
| 134 | 42 | $shared = ($resolved === false) ? array_merge($this->shared, $this->sharedDefinitions) : $this->shared; |
|
| 135 | |||
| 136 | 42 | return (array_key_exists($alias, $shared)); |
|
| 137 | } |
||
| 138 | |||
| 139 | /** |
||
| 140 | * {@inheritdoc} |
||
| 141 | */ |
||
| 142 | 36 | public function add($alias, $concrete = null, $share = false) |
|
| 143 | { |
||
| 144 | 36 | if (is_null($concrete)) { |
|
| 145 | 3 | $concrete = $alias; |
|
| 146 | 3 | } |
|
| 147 | |||
| 148 | 36 | if ($this->isProtected() && $this->has($alias)) { |
|
| 149 | 3 | throw new ProtectedException('Container has been protected, overriding services is not allowed.'); |
|
| 150 | } |
||
| 151 | |||
| 152 | 36 | $definition = $this->definitionFactory->getDefinition($alias, $concrete); |
|
| 153 | |||
| 154 | 36 | if ($definition instanceof DefinitionInterface) { |
|
| 155 | 27 | if ($share === false) { |
|
| 156 | 9 | $this->definitions[$alias] = $definition; |
|
| 157 | 9 | } else { |
|
| 158 | 21 | $this->sharedDefinitions[$alias] = $definition; |
|
| 159 | } |
||
| 160 | |||
| 161 | 27 | return $definition; |
|
| 162 | } |
||
| 163 | |||
| 164 | // dealing with a value that cannot build a definition |
||
| 165 | 9 | $this->shared[$alias] = $concrete; |
|
| 166 | 9 | } |
|
| 167 | |||
| 168 | /** |
||
| 169 | * {@inheritdoc} |
||
| 170 | */ |
||
| 171 | 27 | public function share($alias, $concrete = null) |
|
| 175 | |||
| 176 | /** |
||
| 177 | * {@inheritdoc} |
||
| 178 | */ |
||
| 179 | 12 | public function addServiceProvider($provider) |
|
| 185 | |||
| 186 | /** |
||
| 187 | * {@inheritdoc} |
||
| 188 | */ |
||
| 189 | 6 | public function extend($alias) |
|
| 207 | |||
| 208 | /** |
||
| 209 | * {@inheritdoc} |
||
| 210 | */ |
||
| 211 | public function inflector($type, callable $callback = null) |
||
| 215 | |||
| 216 | /** |
||
| 217 | * {@inheritdoc} |
||
| 218 | */ |
||
| 219 | public function call(callable $callable, array $args = []) |
||
| 223 | |||
| 224 | /** |
||
| 225 | * Marks the container as protected. |
||
| 226 | * |
||
| 227 | * Prevents overriding services and delegating to other containers once the container is marked as protected. |
||
| 228 | */ |
||
| 229 | 6 | public function protect() |
|
| 233 | |||
| 234 | /** |
||
| 235 | * Returns true if the container is protected. |
||
| 236 | * |
||
| 237 | * @return bool |
||
| 238 | */ |
||
| 239 | 45 | public function isProtected() |
|
| 243 | |||
| 244 | /** |
||
| 245 | * Delegate a backup container to be checked for services if it |
||
| 246 | * cannot be resolved via this container. |
||
| 247 | * |
||
| 248 | * @param \Interop\Container\ContainerInterface $container |
||
| 249 | * @return $this |
||
| 250 | */ |
||
| 251 | 12 | public function delegate(InteropContainerInterface $container) |
|
| 265 | |||
| 266 | /** |
||
| 267 | * Returns true if service is registered in one of the delegated backup containers. |
||
| 268 | * |
||
| 269 | * @param string $alias |
||
| 270 | * @return boolean |
||
| 271 | */ |
||
| 272 | 9 | public function hasInDelegate($alias) |
|
| 282 | |||
| 283 | /** |
||
| 284 | * Attempt to get a service from the stack of delegated backup containers. |
||
| 285 | * |
||
| 286 | * @param string $alias |
||
| 287 | * @param array $args |
||
| 288 | * @return mixed |
||
| 289 | */ |
||
| 290 | 12 | protected function getFromDelegate($alias, array $args = []) |
|
| 302 | |||
| 303 | /** |
||
| 304 | * Get a service that has been registered in this container. |
||
| 305 | * |
||
| 306 | * @param string $alias |
||
| 307 | * @param array $args |
||
| 308 | * @return mixed |
||
| 309 | */ |
||
| 310 | 33 | protected function getFromThisContainer($alias, array $args = []) |
|
| 330 | } |
||
| 331 |