Creation of objects

The singleton pattern is one of the well-known software design patterns. It belongs to the group of creation patterns and is often used to provide data or functionality of dedicated objects within a well-defined area of validity.

The APF implements three styles of the pattern for different areas of validity:

  • Singleton: This implementation allows to create objects that are unique within one request. Within subsequent requests the instances loose their validity and are thus created again.
  • SessionSingleton: This class allows you to create objects that are unique within one session. In case the session ends objects created within this context will loos their validity and thus will be created again.
  • ApplicationSingleton: In case you intend to use components throughout several requests and sessions you may want to use this implementation. The status of the instance is maintained as long as the web server is running.
Please note that the areas of validity are only reached in case you retrieve the object instances with the classes listed above in any case or using the ServiceManager or the DIServiceManager.
Using the ApplicationSingleton implementation requires PHP extension APC.
Please be aware to deal with PHP's serialization features using SessionSingleton and ApplicationSingleton. This means that resources (e.g. file pointers, database connections) cannot be serialized and thus need to be re-created within subsequent requests.

The areas of validity listed above can be used to design applications that contain shared elements (e.g. business services, database connections or connections to external systems) that can be configured and used within various components. This does not only lead to better performance but also allows encapsulation of configuration and initialization of certain application parts.

The Adventure PHP Framework implements the abstract singleton pattern and provides different implementations. In contrast to the simple singleton pattern you can create various classes using the available styles but in parallel ensure testability.

The following chapters describe the implementation flavours in depth and contain examples and hints on using them.

1. Singleton

In order to create a unique instance of a class valid within one HTTP request you may want to use the following code:

PHP code
use APF\core\singleton\Singleton; use VENDOR\..\FooModel; $model = Singleton::getInstance('VENDOR\..\FooModel');

In case the instance has not yet been created within the current request it is created for you in the background and returned for further usage. In case the instance has already been created you will receive this instance.

The getInstance() allows to apply an instance identification besides the class to create. This parameter can be used in case more than one instance is used within one application in parallel. You can use this facility in case of multiple database connections based on the same connection implementation.

Usage is as follows:

PHP code
use APF\core\singleton\Singleton; use APF\core\database\MySQLiHandler; $connectionOne = Singleton::getInstance(MySQLiHandler::class, [], 'ConnOne'); $connectionTwo = Singleton::getInstance(MySQLiHandler::class, [], 'ConnTwo');

Both variables $connectionOne and $connectionTwo now contain an instance of the APF\core\database\MySQLiHandler class but with different instance configuration (e.g. different database).

Please note, that each instance (e.g. ConnOne) must be obtained invoking the second parameter calling getInstance(). Otherwise, a new instance will be created.

Using the optional argument $arguments (applied empty within the previous example) you can specify constructor arguments that are applied to the instance to be created. From a software design point of view this has an important benefit as dependencies can directly be expressed as constructor arguments.

In case you want to create an instance of class

PHP code
namespace VENDOR\..\service; class WeatherService { public function __construct($url, DateTime $date) { ... } }

using http://api.openweathermap.org/data/2.5/weather (argument $url) and 14.04.2014 (argument $date) to initialize it you can achieve this easily using the following code block:

PHP code
$service = Singleton::getInstance( 'VENDOR\..\service\WeatherService', [ 'http://api.openweathermap.org/data/2.5/weather', DateTime::createFromFormat('d.m.Y', '14.04.2015') ] );

Using the second argument of the getInstance() method you can specify any number of constructor arguments.

Please note that the order of parameters applied to the getInstance() method must match the order of parameters specified in the constructor of the class to be created! Otherwise, unexpected issues may come up.
Creating an instance with constructor arguments can of course be combined with the definition of an instance identifier.

2. SessionSingleton

In order to create a unique instance of a class valid within one HTTP session and across multiple HTTP requests you may want to create data containers as SessionSingleton instance. To create an instance of a workflow model that is intended to store data from a multi-page workflow you can use the following code:

PHP code
use APF\core\singleton\SessionSingleton; use VENDOR\..\FooModel; $model = SessionSingleton::getInstance('VENDOR\..\FooModel');

In case the the model instance has not been created within the current session it will be created lazily and returned back to the code it is used in. If the object has been requested before you will be returned the previously created instance. This can be used to collect and store user data within a multi-page workflow to be processed at the end of the flow.

The getInstance() allows to apply an instance identification besides the class to create. This parameter can be used in case more than one instance is used within one application in parallel. You can use this facility to allow multiple workflows using the same code base within one application.

Usage is as follows:

PHP code
use APF\core\singleton\Singleton; use VENDOR\..\FooModel; $modelOne = SessionSingleton::getInstance('VENDOR\..\FooModel', [], 'WorkflowOne'); $modelTwo = SessionSingleton::getInstance('VENDOR\..\FooModel', [], 'WorkflowTwo');

Using the optional argument $arguments (applied empty within the previous example) you can specify constructor arguments that are applied to the instance to be created. From a software design point of view this has an important benefit as dependencies can directly be expressed as constructor arguments.

In case you want to create an instance of class FooModel and initialize it at the same time you may want to use the following code block:

PHP code
$model = SessionSingleton::getInstance('VENDOR\..\FooModel', ['foo', 'bar']);

Using the second argument of the getInstance() method you can specify any number of constructor arguments.

Please note that the order of parameters applied to the getInstance() method must match the order of parameters specified in the constructor of the class to be created! Otherwise, unexpected issues may come up.
Creating an instance with constructor arguments can of course be combined with the definition of an instance identifier.

3. ApplicationSingleton

To use information for all visitors and only one time within your application - independent from request and session - you may want to create data containers as ApplicationSingleton instance. This creation method is especially interesting in case object initialization is time-consuming but it can be used across all users and hence across all requests. (e.g. connection to external weather forecast service).

In order to create a service that can be used allover your application please use the following code:

PHP code
use APF\core\singleton\ApplicationSingleton; use VENDOR\..\WeatherService; $service = ApplicationSingleton::getInstance('VENDOR\..\WeatherService');

In case the the model instance has not been created within the current session it will be created lazily and returned back to the code it is used in. If the object has been requested before you will be returned the previously created instance.

The getInstance() allows to apply an instance identification besides the class to create. This parameter can be used in case more than one instance is used within one application in parallel. You can use this facility to allow multiple connections to different weather forecast service using the same service implementation.

Usage is as follows:

PHP code
use APF\core\singleton\ApplicationSingleton; use VENDOR\..\service\WeatherService; $serviceOne = ApplicationSingleton::getInstance('VENDOR\..\service\WeatherService', [], 'ServiceOne'); $serviceTwo = ApplicationSingleton::getInstance('VENDOR\..\service\WeatherService', [], 'ServiceTwo');

Using the optional argument $arguments (applied empty within the previous example) you can specify constructor arguments that are applied to the instance to be created. From a software design point of view this has an important benefit as dependencies can directly be expressed as constructor arguments.

In case you want to create an instance of class WeatherService and initialize it at the same time you may want to use the following code block:

PHP code
$service = ApplicationSingleton::getInstance( 'VENDOR\..\service\WeatherService', [ 'http://api.openweathermap.org/data/2.5/weather', DateTime::createFromFormat('d.m.Y', '14.04.2015') ] );

Using the second argument of the getInstance() method you can specify any number of constructor arguments.

Please note that the order of parameters applied to the getInstance() method must match the order of parameters specified in the constructor of the class to be created! Otherwise, unexpected issues may come up.
Creating an instance with constructor arguments can of course be combined with the definition of an instance identifier.

4. Further reading

Based on the creation methods described in chapter 1 (Singleton), chapter 2 (SessionSingleton) und chapter 3 (ApplicationSingleton) the APF offers further tools to create, configure and maintain object instances.

The ServiceManager offers an abstraction of the above-listed methods and helps to configure the created objects.

The DIServiceManager is an dependency injection container that helps to separate code and configuration as well as to decouple components within your application to ensure exchangeability and testability.

Creating complex applications it is recommended to to use the DIServiceManager to create instances since the above-listed mechanisms do not provide configuration facilities.

Comments

Do you want to add a comment to the article above, or do you want to post additional hints? So please click here. Comments already posted can be found below.
There are no comments belonging to this article.