Singleton in Conjunction with the Factory Pattern in PHP5 - php

What is the best method for using singleton design pattern in conjunction with the factory method pattern in PHP5? My simplest usage scenario for this is instantiation selective database connection only once for each database type.

singleton factory for DB connection:
class Registry
{
private static $_objects;
public static function set($key, $object)
{
if (!array_key_exists($key, self::$_objects)) self::$_objects[$key] = $object;
}
public static function get($key)
{
if (array_key_exists($key, self::$_objects)) return self::$_objects[$key];
else return false;
}
}
class DBFactory
{
public static function getConnection($type)
{
switch ($type) {
case 'pdo':
if (!(Registry::get('DB_PDO') instaceof DbPdo)) Registry::set('DB_PDO', new DbPdo('user', 'pass', ...));
return Registry::get('DB_PDO')
case 'mssql':
//same for other connections
//...
}
}
}
usage:
$factory = DBFactory::getConnection('pdo');
Singletons are not really needed anymore because all methods can be called statically...
But the database classes can still be considered singletons because there will only be one single instance of them in your application.
So the same effect is created by using the factory and registry patterns.
The registry could be replaced by making your database classes singletons then the factory would look like this:
class DBFactory
{
public static function getConnection($type)
{
switch ($type) {
case 'pdo':
return DbPdo::getInstance('user', 'pass', ...);
case 'mssql':
//same for other connections
//...
}
}
}
class DbPdo
{
private static $_instance;
private function __construct($user, $pass, ...){ //instantiate object }
public static function getInstance($user = null, $pass = null, ...)
{
if (!(self::$_instance instanceof DbPdo)) self::$_instance = new DbPdo($user, $pass, ...);
return self::$_instance;
}
}
So you have the choice of making all your DB objects singletons or using a registry. I personally would go with a registry because it can be used to store any types of object, even the ones where you don't want to make the class a singleton.
Design choices are always subjected to personal flavor imo...

Related

incapsulation and non exposing internals vs SRP

Is code like this is a bad? :
public class TierType
{
private const TYPE_HARD = 'hard';
private const TYPE_MEDIUM = 'medium';
private const TYPE_SOFT = 'soft';
private const SUPPORTED_TYPES = [
self::TYPE_HARD,
self::TYPE_MEDIUM,
self::TYPE_SOFT
];
private function _construct(private string $type) {
}
public static function fromString(string $tierType): self
{
return match ($tierType) {
self::TYPE_HARD => new self(self::TYPE_HARD),
self::TYPE_MEDIUM => new self(self::TYPE_MEDIUM),
self::TYPE_SOFT => new self(self::TYPE_SOFT),
default => throw new Exception('Unsupported tier type provided'),
};
}
public static function createHard(): self
{
return new self(self::self::TYPE_HARD)
}
public static function createMedium(): self
{
return new self(self::self::TYPE_MEDIUM)
}
public static function createSoft(): self
{
return new self(self::self::TYPE_SOFT)
}
}
In this example we not exposing internals of the object, and not delegating creation of the object to outer world, and it's a way I like to do it, and doing for a while already. But recently I heard that is' wrong and it's breaking a SRP as it's not responsibility of object to create it self, and you need to have a public constructor and initiate object from factory. Like this:
public class TierType
{
public const TYPE_HARD = 'hard';
public const TYPE_MEDIUM = 'medium';
public const TYPE_SOFT = 'soft';
public const TYPE_EXTRA_SOFT = 'extra_soft';
private const SUPPORTED_TYPES = [
self::TYPE_HARD,
self::TYPE_MEDIUM,
self::TYPE_SOFT
];
public function _construct(private string $type) {
if (!in_array($this->type, self:::SUPPORTED_TYPES) {
throw new Exception('Unsupported tier type provided')
}
}
}
public class TierFactory {
public function create(string $type): TierType
{
return match ($type) {
self::TYPE_HARD => new TierType(TierType::TYPE_HARD),
self::TYPE_MEDIUM => new TierType(TierType::TYPE_MEDIUM),
self::TYPE_SOFT => new TierType(TierType::TYPE_SOFT),
default => throw new Exception('Unsupported tier type provided'),
};
}
public static function createHard(): TierType
{
return new TierType(TierType::TYPE_HARD)
}
public static function createMedium(): TierType
{
return new TierType(TierType::TYPE_MEDIUM)
}
public static function createSoft(): TierType
{
return new TierType(TierType::TYPE_SOFT)
}
}
I think it also okay, but in this case it's probably unnecessary to create factory as logic is simple, and we allowing other devs to omit that factory and directly call TierType constuctor or create other types of factories. Hopefully we have a validation in the constructor but what if not?? it's harder to thing about object state and add all validation when you delegating it to many classes. From other hadn I think class should tell it's self how to create it, and provide interface of creation. I agree that factory make sense if logic of creation is complicated and some part of it it's not related to object, for example we need to take data from different sources, combine it somehow and after that pass to the object, in that case it's not object responsibility.
Am I thinking correctly??? Or it's really breaking SRP and it's okay to delegate it to factory???
Single Responsibility should be understood as an abstraction of logical tasks in your system. A class should have the single responsibility to perform one single, specific task. A class that manages its own creation doesn't necessarily violates SRP.
That being said, there is a third option to do this that seems more elegant for your specific example. Create separate classes for each different types, each class extending from a common class:
public class TypeHard extends TierType implements TierTypeInterface {
public function __construct()
{
parent::__construct(parent::TYPE_HARD);
}
}
This way is also easier to use with autowired DI containers.

PHP - Good design pattern for static database connection class

I have a "static" class which connects to database and has various functions. The current base layout is as follows:
class DB {
private static $con;
private function __construct() {};
private static function init() {
if(is_null(self::$con) {
// Initialize database connection
}
}
public static someMethod1() {
self::init();
// Do stuff
}
public static someMethod2() {
self::init();
// Do stuff
}
public static someMethod2() {
self::init();
// Do stuff
}
}
My intention is to be easily be able to call these methods as: DB::someMethod1(). However, as you can see, I am having to cehck for initialization at every method beginning. Is this a good coding practice? Is there a better design pattern available? Initially I thought of builder pattern but that doesn't really fit here in my opinion.
It looks like you are trying to ensure that there is a single instance of your DB class AND also that the instance is available as a single, globally available constant.
I'd recommend separating those two concerns in order to simplify the implementation.
First, I'd focus on getting the database access object right. Plain objects are simpler to test and inject as dependencies than static functions. For example,
class DBThing
{
private $con;
public static function build()
{
return new static('theconnection');
}
function __construct($con)
{
$this->con = $con;
}
public function someMethod1()
{
echo "someMethod1: $this->con\n";
}
public function someMethod2()
{
echo "someMethod2: $this->con\n";
}
public function someMethod3()
{
echo "someMethod3: $this->con\n";
}
}
Gives you an object you can easily test and replace with alternate implementations if needed.
Second, I'd focus on the object lifecycle and making it discoverable in the application.
If you're really OK with a single instance and the global state that implies, then something like this gets you close to the interface you asked for in your original post.
$DB = DBThing::build();
$DB->someMethod1();
$DB->someMethod2();
$DB->someMethod3();
In general, I discourage global state but I'd have to know more about your application to know if it's appropriate in your case.
I just wrote a simple db class for a coding test. Take a look at how I used here: https://github.com/TheRealJAG/Valuation-Vision-Full-Stack-Test/blob/master/classes/db.php
class DB
{
private static $instance = null;
private $db;
private $host = '';
private $username = '';
private $password = '';
private $database = '';
private function __construct()
{
$this->db = new mysqli($this->host, $this->username, $this->password, $this->database);
if ($this->db->connect_error) {
throw new Exception("Connection to the mysql database failed: " . $this->db->connect_error);
}
}
public static function connection()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance->db;
}
}
I'm 100% sold on the approach, but with the time I had for the test this is what I wrote. My biggest concern was that I only had 1 db connection open.

Singleton to factory in PHP

There are many topics about this already, but I have not a clear picture of why factory patterns are better practice than Singleton.
An example
class MySingleton {
public static function numberByWhat( $number ) {
return $number + 100;
}
public static function someCharacters( $string ) {
return $string + 'abc';
}
}
class MyOtherSingleton {
public static function getImage( $url ) {
return '<img src="' . $url . MySingleton::numberByWhat( $50 ) . '">';
}
public static function getTextById( $id ) {
if( $id == 3 ) {
return 'this is my text' . MySingleton::someCharacters( 'Yeah' );
}
}
}
function run() {
echo MyOtherSingleton::getImage( 'http://www.example.com/image.png' );
echo MyOtherSingleton::getTextById( 3 );
}
run();
So there we have 2 classes and a function. When I run() I start a function in the second class. Inside the functions in the second class there are calls to the first class.
How would this look like as a factory pattern?
Why is it better as a factory pattern?
So the examples you've given are neither Singletons nor Factories. What you have here are simply "static classes"--classes with only static methods and properties. Factories and Singletons don't really solve the same problem, either, so it's difficult to compare and contrast them.
Singletons
A Singleton is used to manage shared state or avoid the overhead of instantiating a class multiple times when you only really need "one of something".
Here's an example of a Singleton:
class DatabaseConnection {
// Static reference to the single instance of this class we maintain.
protected static $instance;
// Normal instance properties.
protected $mysql;
// Protected constructor to prevent "new DatabaseConnection();"
protected function __construct() {
$this->mysql = new MySQLConnection("localhost", 3306, "appdb");
}
public static function getInstance() {
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function query($sql) {
return $this->mysql->query($sql);
}
}
Whenever you want to use the DatabaseConnection() in your code, you do it like this:
function getUser($userId) {
$userData = DatabaseConnection::getInstance()->query("SELECT * FROM ...");
}
The DatabaseConnection() is only instantiated once, starting the first time it is used. There will never be more than one created.
Dependency Injection / Inversion of Control
The competing strategy to using a Singleton is, basically, Dependency Injection or Inversion of Control. With Dependency Injection, instead of having one shared, staticly-stored instance of a class, the instance is simply passed from class to class and function to function. Here's a simple example:
class DatabaseConnection {
// Normal instance properties.
protected $mysql;
public function __construct() {
$this->mysql = new MySQLConnection("localhost", 3306, "appdb");
}
public function query($sql) {
return $this->mysql->query($sql);
}
}
class UserManager {
protected $databaseConnection;
public function __construct(DatabaseConnection $databaseConnection) {
$this->databaseConnection = $databaseConnection;
}
public function lookupUser($userId) {
return $this->databaseConnection->query("SELECT ...");
}
}
One advantage of Dependency Injection is that you can test your code much more easily. You could, for example, extend DatabaseConnection and call it TestDatabaseConnection, and make it not actually use a real MySQL database, which can make your tests faster and more reliable. So, the debate is really between Singletons and Dependency Injection / Inversion of Control, not Factories.
Factories
So, now, Factories: Factories simplify the creation of objects, return objects of different classes/subclasses, and help to create objects from "templates". As an example, let's say we have different classes to represent different types of users:
class User {
// ...
}
class ModeratorUser extends User {
// ...
}
class AdminUser extends ModeratorUser {
// ...
}
class GuestUser extends User {
// ...
}
Each of these classes contain methods and properties that would be useful for working with a certain type of user account. So, how would you create and return one of these user objects by User ID, ensuring that the correct type of user is returned? We can use a factory pattern:
class UserFactory {
public static function fromUserId(DatabaseConnection $db, $userId) {
$record = $db->query("SELECT * FROM users WHERE user_id ...");
// ...
switch ($record['type']) {
case 'admin':
return new AdminUser($userId);
break;
case 'moderator':
return new ModeratorUser($userId);
break;
case 'guest':
return new GuestUser($userId);
break;
default:
case 'normal':
return new User($userId);
break;
}
}
}
Then, to load the proper User class, you'd just call:
$user = UserFactory::fromUserId($userId);
If it's an admin account, it will be an AdminUser; if it's a guest account, it will be a GuestUser.

PHP prevent parent class from multiple instantiation from children?

So currently my class DATABASE uses a singleton for a connection and is called in the constructor of my class SQL. I have 4 other classes that extend class SQL for access to its methods. The problem is, the children instantiate each other in some cases so I'm afraid I'm creating multiple class SQL objects because they call their parent constructor by default, aka class SQL. I read about dependency injection, but no clear how to implement it in my situation so this is what I was thinking.
Have all classes extend class DATABASE and make class SQL methods static.
But then I would have to call the singleton connection in class DATABASE, on its own class as so.
class DATABASE {
function __construct() {
self::getInstance();
/// or DATABASE::getInstance ( im not quite positive which way )
}
public static function getInstance() {
if (self::$instance == false) {
self::$instance = new DATABASEMANAGER();
}
return self::$instance;
}
}
I figure this way, since all classes extend class DATABASE, and instantiate each other, I know I am not creating multiple objects.
I hope this makes sense and I can elaborate more if you need me to, but does this make since as an approach to my problem?
I guess you building your class other way around, this approach is more consistent in my opinion.
class DATABASE extends DATABASEMANAGER
{
static $instance;
private function __construct()
{
parent::__construct();
}
public static function getInstance()
{
if (empty(self::$instance))
{
self::$instance = new self();
}
return self::$instance;
}
}
Usage:
class Blog
{
public function __construct()
{
$this->database = DATABASE::getInstance();
}
public function getRecord($id)
{
$result = $this->database->query("SELECT * FROM blog WHERE id='{$id}'");
//or
$result = DATABASE::getInstance()->query("SELECT * FROM blog WHERE id='{$id}'");
//other actions...
}
}

Registry pattern and lazy instantiation of registered objects

Let's imagine that we have Registry pattern...
<?php
class Registry
{
private static $objects = array();
private static $instance = null;
public static function getInstance() {
if (self::$instance == null) {
self::$instance = new Registry();
}
return self::$instance;
}
protected function _get($key) {
return ($this->objects[$key]) ? $this->objects[$key] : null;
}
protected function _set($key, $val) {
$this->objects[$key] = $val;
}
public static function get($key) {
return self::getInstance()->_get($key);
}
public static function set($key, $object) {
return self::getInstance()->_set($key, $object);
}
}
?>
Using this realization is really easy...
<?
Registry::set('db', $db_client);
Registry::set('redis', $redis_client);
//Using registered objects is really easy
Registry::get('db')->query("...");
Registry::get('redis')->get("...");
?>
But as you can see, we're adding instances into registry even if we don't need them (yes, it's all about performance).
So, the question is... How to modify Registry pattern to be able to do lazy instantiation?
Here is what I'm looking for...
<?
class Registry
{
private static $objects = array();
private static $instance = null;
public static function getInstance() {
if (self::$instance == null) {
self::$instance = new Registry();
}
return self::$instance;
}
protected function _db() {
if (!$this->objects['db']) {
$this->objects['db'] = new DatabaseAdapter(DB_HOST, DB_NAME, DB_USER, DB_PASSWORD);
}
return $this->objects['db'];
}
protected function _redis() {
if (!$this->objects['redis']) {
$this->objects['redis'] = new Redis(REDIS_HOST, REDIS_DB, REDIS_USER, REDIS_PASSWORD);
}
return $this->objects['redis'];
}
public static function db() {
return self::getInstance()->_db();
}
public static function redis() {
return self::getInstance()->_redis();
}
}
?>
As you can see, DatabaseAdapter() or Redis() will be created only in we'll request them. Everything seems to be ok, but as you can see it's not a standalone class because _db(), _redis() methods contains connection constants etc.
How to avoid it? How can I define registry method within registry class to separate Registy class and objects inside it?
I'm really sorry about my English, but I hope it is clear for you.
Thank you.
PS: All code above was written 1 min. ago and wasn't tested.
If you use global constants you will always have a dependency on the global scope. It doesnt matter where it is. Also, even if you do not use constants, you still have the dependency on the Database class inside the Registry. If you want to dissolve those dependencies, you could use Factory methods on the to be created classes:
public function get($service)
{
if( !this->_data[$service] ) {
// requires PHP 5.2.3
this->_data[$service] = call_user_func($service .'::create');
}
return this->_data[$service];
}
So if you do get('DB'), the code would try to call the static DB::create() method inside the class you intend to create. But like I said, if you use global Constants for the configuration, you would just move the problem into another class.
Your db class could look like this:
class DB
{
protected static $_config;
public static setConfig(array $config)
{
self::_config = $config;
}
public static create()
{
return new self(
self::config['host'],
self::config['db'],
self::config['user'],
self::config['pass']);
}
}
The configuration can be stored inside an external configuration file, which you load and set to the DB class during bootstrap, e.g.
DB::setConfig(parse_ini_file('/path/to/db-config.ini'));
The disadvantage of this is, you have to add create() methods all over the place and all classes must be able to store their own configuration. You could centralize these responsibilities into a Builder pattern. But if you do this, you are half way to implementing an IoC Container anyways, so check out the following resources:
Fabien Potencier: What is Dependency Injection
Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern
Design pattern – Inversion of control and Dependency injection
Note: You are using a "static" modifier for $objects - as you are working with an instance, this is probaby not necessary.
How can I define registry method within registry class to separate Registy class and objects inside it?
They are always separate: Each object inside the registry class is just a reference to the (independent) object. But if this question is about including the appropriate class definition (?) you may use the class_exists() function to load the class as soon as required.
BurninLeo

Categories