MediaWiki REL1_31
ServiceContainer.php
Go to the documentation of this file.
1<?php
2namespace MediaWiki\Services;
3
4use InvalidArgumentException;
5use RuntimeException;
6use Wikimedia\Assert\Assert;
7
47
51 private $services = [];
52
57
61 private $disabled = [];
62
67
71 private $destroyed = false;
72
79 $this->extraInstantiationParams = $extraInstantiationParams;
80 }
81
90 public function destroy() {
91 foreach ( $this->getServiceNames() as $name ) {
92 $service = $this->peekService( $name );
93 if ( $service !== null && $service instanceof DestructibleService ) {
94 $service->destroy();
95 }
96 }
97
98 $this->destroyed = true;
99 }
100
106 public function loadWiringFiles( array $wiringFiles ) {
107 foreach ( $wiringFiles as $file ) {
108 // the wiring file is required to return an array of instantiators.
109 $wiring = require $file;
110
111 Assert::postcondition(
112 is_array( $wiring ),
113 "Wiring file $file is expected to return an array!"
114 );
115
116 $this->applyWiring( $wiring );
117 }
118 }
119
127 Assert::parameterElementType( 'callable', $serviceInstantiators, '$serviceInstantiators' );
128
129 foreach ( $serviceInstantiators as $name => $instantiator ) {
130 $this->defineService( $name, $instantiator );
131 }
132 }
133
144 public function importWiring( ServiceContainer $container, $skip = [] ) {
145 $newInstantiators = array_diff_key(
146 $container->serviceInstantiators,
147 array_flip( $skip )
148 );
149
150 $this->serviceInstantiators = array_merge(
151 $this->serviceInstantiators,
152 $newInstantiators
153 );
154 }
155
164 public function hasService( $name ) {
165 return isset( $this->serviceInstantiators[$name] );
166 }
167
183 public function peekService( $name ) {
184 if ( !$this->hasService( $name ) ) {
185 throw new NoSuchServiceException( $name );
186 }
187
188 return isset( $this->services[$name] ) ? $this->services[$name] : null;
189 }
190
194 public function getServiceNames() {
195 return array_keys( $this->serviceInstantiators );
196 }
197
212 public function defineService( $name, callable $instantiator ) {
213 Assert::parameterType( 'string', $name, '$name' );
214
215 if ( $this->hasService( $name ) ) {
217 }
218
219 $this->serviceInstantiators[$name] = $instantiator;
220 }
221
238 public function redefineService( $name, callable $instantiator ) {
239 Assert::parameterType( 'string', $name, '$name' );
240
241 if ( !$this->hasService( $name ) ) {
242 throw new NoSuchServiceException( $name );
243 }
244
245 if ( isset( $this->services[$name] ) ) {
247 }
248
249 $this->serviceInstantiators[$name] = $instantiator;
250 unset( $this->disabled[$name] );
251 }
252
272 public function disableService( $name ) {
273 $this->resetService( $name );
274
275 $this->disabled[$name] = true;
276 }
277
301 final protected function resetService( $name, $destroy = true ) {
302 Assert::parameterType( 'string', $name, '$name' );
303
304 $instance = $this->peekService( $name );
305
306 if ( $destroy && $instance instanceof DestructibleService ) {
307 $instance->destroy();
308 }
309
310 unset( $this->services[$name] );
311 unset( $this->disabled[$name] );
312 }
313
334 public function getService( $name ) {
335 if ( $this->destroyed ) {
336 throw new ContainerDisabledException();
337 }
338
339 if ( isset( $this->disabled[$name] ) ) {
340 throw new ServiceDisabledException( $name );
341 }
342
343 if ( !isset( $this->services[$name] ) ) {
344 $this->services[$name] = $this->createService( $name );
345 }
346
347 return $this->services[$name];
348 }
349
356 private function createService( $name ) {
357 if ( isset( $this->serviceInstantiators[$name] ) ) {
358 $service = call_user_func_array(
359 $this->serviceInstantiators[$name],
360 array_merge( [ $this ], $this->extraInstantiationParams )
361 );
362 // NOTE: when adding more wiring logic here, make sure copyWiring() is kept in sync!
363 } else {
364 throw new NoSuchServiceException( $name );
365 }
366
367 return $service;
368 }
369
375 public function isServiceDisabled( $name ) {
376 return isset( $this->disabled[$name] );
377 }
378}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
Exception thrown when trying to replace an already active service.
Exception thrown when trying to access a service on a disabled container or factory.
Exception thrown when the requested service is not known.
Exception thrown when a service was already defined, but the caller expected it to not exist.
ServiceContainer provides a generic service to manage named services using lazy instantiation based o...
redefineService( $name, callable $instantiator)
Replace an already defined service.
bool[] $disabled
disabled status, per service name
disableService( $name)
Disables a service.
importWiring(ServiceContainer $container, $skip=[])
Imports all wiring defined in $container.
getService( $name)
Returns a service object of the kind associated with $name.
applyWiring(array $serviceInstantiators)
Registers multiple services (aka a "wiring").
destroy()
Destroys all contained service instances that implement the DestructibleService interface.
resetService( $name, $destroy=true)
Resets a service by dropping the service instance.
defineService( $name, callable $instantiator)
Define a new service.
hasService( $name)
Returns true if a service is defined for $name, that is, if a call to getService( $name ) would retur...
__construct(array $extraInstantiationParams=[])
peekService( $name)
Returns the service instance for $name only if that service has already been instantiated.
Exception thrown when trying to access a disabled service.
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
the array() calling protocol came about after MediaWiki 1.4rc1.
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:302
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition injection.txt:37
DestructibleService defines a standard interface for shutting down a service instance.