Is this enought to make singleton in php?
public static function getInstance() {
if (!isset(self::$intance)) {
self::$instance = new mysqli(DB_HOST, DB_USER, DB_PWD, DB_NAME);
}
return self::$instance;
}
I found it easiest way, more easy than anything I saw here. Can there be any problems with that?
You can't make the original mysqli class be a singleton - which is actually a good thing because singletons are evil (and I will go into details about this if needed).
What you did is technically called a static factory method that will only return the first ever created instance of the database object. This is in fact very much better than using a singleton because you might also delete that instance for testing to create another one, and another one ...
But from my experience, you are usually happy to have a way to use more than exactly one database connection in your code. Simply think about using two user accounts, one for admin stuff, and the other one for regular usage. This alone would qualify as two database connections, and if your code can only handle "the only one instance" without a choice of login credentials, this would be really a bad thing. I'd recommend against it.
This is singleton class:
class DataBase
{
private static $mysqli;
final private function __construct() {}
public static function getInstance()
{
if (!is_object(self::$mysqli)) self::$mysqli = new mysqli($H,$U,$P,$B);
return self::$mysqli;
}
private function __destruct()
{
if (self::$mysqli) self::$mysqli->close();
}
private function __clone() {}
}
It's important that:
variable (storing db connection) is static
constructor function is private (cannot be called) (final that cannot be overridden)
function returning object is static as well (usually function getInstance as here)
cloning of singleton classes is not allowed so __clone() function must be empty
destructor function __destruct is called by garbage collector and should finalize state
so this database connection is called from other classes as:
$db=DataBase::getInstance();
not as
$db=new DataBase();
Consolidating the changes in the comments, with one of my own. Rather than relying on constants, pass the variables into the getInstance/constructor so that you can store your credentials any way you would like, and feed them into the class, without having the class be reliant on the data being stored a certain way. Adds a bit of flexibility.
You can also swap that out with code to read them from a config file, or to pick up the data from a service locator type pattern.
Class MysqlConnection {
private static $instance = null;
private function __construct() {
self::$instance = new mysqli(DB_HOST,DB_USER,DB_PASS,DB_DATABASE);
}
public static function getInstance() {
if (!isset(self::$instance)) {
$credentials = self::getCredentials();
self::$instance = new MysqlConnection();
}
return self::$instance;
}
}
function __clone() {
//Throw exception/custom exception type here.
}
}
Edit Comment: The idea is not to outline an entirely 100% use as is class here, but to represent my position and approach to this. The credentials bit is not 100% necessary, its just how I feel about making it a little more flexible, rather than hard coding it to use only CONSTANTS, etc. That might distract from the initial point, which is what does a singleton look like. I apologize for the confusion.
Related
I'm attempting to design my website based on OOP, but I'm having trouble with how to design the database connection. Currently, I'm creating a private static PDO object in an abstract class, Connector. Obviously, anything that needs to interact with the database will extend this class. I've been flipping back and forth on how to make sure that there is only ever one connection, or PDO object, in a script because some pages will need more than one class that extends Connector. Many people seem to recommend a Singleton pattern for this purpose, but the way I currently do it seems to accomplish the same thing.
Here's my current code.
abstract class Connector
{
private static $dbh;
public function __construct()
{
try
{
self::$dbh = new PDO(...);
self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
die($e->getMessage());
}
}
public function getDB()
{
return self::$dbh;
}
}
Then any subclasses would use it like this.
class Subclass extends Connector
{
public function interactWithDB()
{
$stmt = $this->getDB()->prepare(...);
// etc...
}
}
Theoretically, each instance of a subclass should always be accessing the same PDO instance, I think. Does this code actually make sense and or am I misunderstanding static properties somehow? Is it bad design/practice and or does Singleton have more advantages?
Comment if something's not clear, thanks!
EDIT:
The Connector class wasn't meant to exist just to hold the PDO object. It's destructor closes the connection(makes it null) and it contains functions such isValueTaken, which checks if a value is already in the database. It has the following abstract functions
abstract function retrieveData();
abstract function setData();
For example I have a User class that extends Connector. It's defines setData() to register a user in the database. I don't know if this makes a difference to the response.
Obviously, anything that needs to interact with the database will extend this class.
This really makes no sense from an OOP perspective. When some class extends another class that implies an "is a" relationship. If you go this route you are going to have a hard time not violating OCP which is one of the letters in SOLID.
I've been flipping back and forth on how to make sure that there is only ever one connection, or PDO object, in a script because some pages will need more than one class that extends Connector.
Easy! Just create one instance.
Many people seem to recommend a Singleton pattern for this purpose, but the way I currently do it seems to accomplish the same thing.
Many people like that have no clue about OOP principles. Using an singleton just introduces a "fancy" global instance / state.
Does this code actually make sense and or am I misunderstanding static properties somehow?
To be honest it is more a misunderstanding of OOP.
Is it bad design/practice and or does Singleton have more advantages?
See above.
What you should do (in OOP) is inject the database connection into the classes that need it. This makes your code loosely coupled which in turn makes your code better maintainable, testable, debuggable and flexible.
Also I don't really see why you need to create a database class for a pdo connection, because the PDO API itself is already OOP. So unless you have a real reason to write a adapter (can be the case, because there are some) for PDO I would just drop it.
My €0.02
--
In response to your edit:
The Connector class wasn't meant to exist just to hold the PDO object. It's destructor closes the connection(makes it null).
There is often no need at all to close the connection. The connection will automatically be closed once the request is handled (unless we are talking about a persistent connection).
and it contains functions such isValueTaken, which checks if a value is already in the database. It has the following abstract functions
That sounds like a job for another class.
For example I have a User class that extends Connector. It's defines setData() to register a user in the database. I don't know if this makes a difference to the response.
No my point still stands. There is no need for a user to inherit from a database. Doesn't that sounds strange. A user inheriting from a database (I don't want to meet that person). You should inject the database connection into the User if it is needed.
Preface
The singleton approach is generally frowned upon. You will be set upon by raptors.
What you're essentially asking is how to configure a connection and make it globally available. This is generally referred to as global state. You can achieve this using a container class and static methods.
Here's an example
namespace Persistence\Connection\Config;
interface PDOConfig {
public function getDSN();
public function getUsername();
public function getPassword();
public function getDriverOptions();
}
class MySqlConfig implements PDOConfig {
private $username;
private $password;
private $db;
private $host = 'localhost';
private $charset = 'utf8';
public function __construct($username, $password, $db) {
$this->username = $username;
$this->password = $password;
$this->db = $db;
}
// getters and setters, etc
public function getDSN() {
return sprintf('mysql:host=%s;dbname=%s;charset=%s',
$this->host, $this->db, $this->charset);
}
public function getDriverOptions() {
return [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
}
}
namespace Persistence\Connection;
use Persistence\Connection\Config\PDOConfig;
class Registry {
private static $connection;
private static $config;
public static function setConfig(PDOConfig $config) {
self::$config = $config;
}
public static getConnection() {
if (self::$connection === null) {
if (self::$config === null) {
throw new RuntimeException('No config set, cannot create connection');
}
$config = self::$config;
self::$connection = new \PDO($config->getDSN(), $config->getUsername(),
$config->getPassword(), $config->getDriverOptions());
}
return self::$connection;
}
}
Then, at some point (early) in your application execution cycle
use Persistence\Connection\Config\MySqlConfig;
use Persistence\Connection\Registry;
$config = new MySqlConfig('username', 'password', 'dbname');
Registry::setConfig($config);
Then, you can use
Registry::getConnection();
anywhere in your code to retrieve the PDO instance.
Just a side note if anyone is reading this, if anybody is using the above code snippet by Phil, remember to use a black slash infront of PDO inside getDriverOptions() so as to refer to the global namespace. it should look like this.
public function getDriverOptions() {
return [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => false,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC
];
}
To be clear, I don't want to instantiate the same class multiple times. I only want to instantiate it once, and keep track of any changes made to that instance via some reference. Is this possible, and if so how can it be done? Thanks!
You can use the Singleton pattern for this. The PHP manual has a good example and description:
The Singleton ensures that there can be only one instance of a Class and provides a global access point to that instance.
Class:
<?php
class Example
{
private static $instance;
private function __construct() {
}
public static function singleton() {
if (!isset(self::$instance)) {
echo 'Creating new instance.';
$className = __CLASS__;
self::$instance = new $className;
}
return self::$instance;
}
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Unserializing is not allowed.', E_USER_ERROR);
}
}
Usage:
$singleton = Example::singleton();
It is worth also noting these objections to the singleton pattern from the PHP manual:
The Singleton pattern is one of the more controversial patterns. Critics argue that
Singletons introduce Global State into an application and tightly
couple the Singleton and its consuming classes. This leads to hidden
dependencies and unexpected side-effects, which in turn leads to code
that is harder to test and maintain.
Critics further argue that it is pointless to use a Singleton in a
Shared Nothing Architecture like PHP where objects are unique within
the Request only anyways. It is easier and cleaner to create
collaborator object graphs by using Builders and Factory patterns once
at the beginning of the Request.
Singletons also violate several of the "SOLID" OOP design principles
and the Law of Demeter. Singletons cannot be serialized. They cannot
be subtyped (before PHP 5.3) and won't be Garbage Collected because of
the instance being stored as a static attribute of the Singleton.
See as well: Who needs singletons?
You can create Singleton pattern
class Something {
private static $instance;
private function __construct() {
}
public static function getInstance() {
if(Something::$instance == null) {
Something::$instance = new Something();
}
return Something::$instance;
}
public function someMethod() {
return "abc";
}
}
When you want to use it you call Something::getInstance()->someMethod()
Read more about singleton pattern.
To be clear, I don't want to instantiate the same class multiple times. I only want to instantiate it once, and keep track of any changes made to that instance via some reference. Is this possible, and if so how can it be done? Thanks!
Sure this is possible. You can do this literally:
First of all, as you don't want to instantiate the class multiple times, just instantiate it once:
$instance = new Class();
Then you want to keep track of changes made to that instance. I don't specifically know what you mean. Probably you mean to only keep that one instance. You just can do so, as you have only instantiated once, you can refer to that instance with the $instance variable.
Additionally you can "reference" that $instance as well in some other variable:
$reference = $instance;
You can now access the single instance of Class with the $instance and the $reference variable.
If you need to monitor the instance, I suggest you create a Decorator that does the job:
$decorator = new ClassDecorator(new Class());
The decorator can then work as an interceptor before anything reaches Class.
To find out if the inner state of a class has changed or not, you can make use of the serialize and unserialize functions as well:
$instance = new Class();
$snapshot = serialize($instance);
...
# more code, $instance is changed or not, we don't know
...
$changed = $snapshot != serialize($instance);
Hope this is helpful.
What you are trying to do is called the Singleton Pattern .. See http://en.wikipedia.org/wiki/Singleton_pattern
An ethical question here.
I'm planning on using several manager classes in my new project that will be performing various tasks across the whole project. These classes are singletons, but require construction based on parameters.
As to when/where this construction has to happen, I have mixed feelings. I have these options so far:
Option A
It's easy to just pass these parameters to the getInstance method while having a default null value. On the very first call the parameters will be used, and any additional calls completely ignore them.
While this works, doing so feels rather unlogical, for the following reasons:
It makes documentation unclear. getInstance' first parameter must be of type Collection, but can be null... what's going on here?
You can argue that writing a line about this in the description will clear it up, but I'd prefer clarification to be unneccesary.
It feels faulty to pass getInstance any construction parameters. This is due to the fact that the method name does not explicity hint towards construction, making it unclear it will happen.
Option B
I'm thinking about a setup method. This method takes all parameters, calls the class constructor, and changes the internal class state to initialized.
When calling the getInstance method prior to setup, it will throw a NotInitializedException. After setup has been called, any additional calls to setup will result in a PreviouslyInitializedException.
After setup has been called, getInstance becomes available.
Personally, this option appeals more to me. But it feels excessive.
What option do you prefer? And why?
I would probably try and ditch the singleton approach and pass manager classes around to whatever needs them.
$manager = new Manager( $collection, $var, $var2 );
$other_class = New OtherClass( $manager );
//or
$other_class = New OtherClass;
$other_class->manager = $manager;
//or
$other_class = New OtherClass;
$other_class->setManager( $manager );
Use dependency injection to pass the Manager object around. Don't use Singleton pattern. It's a common consensus that using it creates a global state and makes your API deceptive.
PHP Global in functions (jump to answer)
Singletons are pathological liars
Inject the Manager instance to any class that needs it via the constructor. Each class should not try to instantiate Manager by themselves, the only way the classes get an instance of the Manager is by getting it from constructor.
class NeedsManager
{
protected $manager;
public function __construct(Manager $manager)
{
$this->manager = $manager;
}
}
You don't need to enforce one instance of Manager. Just don't instantiate it more than once. If all of your classes that need an instance of Manager get what they need from the constructor and never tries to instantiate it on their own, it will assure that there's just going to be one instance in your application.
How about option 3. If they are true singletons, set up properties files for their parameters for use with a no-arg getInstance.
If that doesn't fit, you might be misusing the singleton pattern.
You are looking at using a Factory design pattern. Factories are objects that act as fancy constructors for other objects. In your case, you will move setup and getInstance to the factory. The wiki article's pretty good- http://en.wikipedia.org/wiki/Factory_method_pattern
class SingletonFoo {
//properties, etc
static $singleton = NULL;
private function __constructor(){}
static function getInstance(){
if(NULL === self::$singleton) {
self::$singleton = new SingletonFoo();
}
return self::$singleton;
}
}
class FooFactory {
static $SingletonFoo = null;
static function setup($args){
if( !(NULL === self::$SingletonFoo)){
throw new AlreadyInstantiatedException();
}
self::$SingletonFoo = SingletonFoo::getInstance();
//Do stuff with $args to build SingletonFoo
return self::$SingletonFoo;
}
static function getInstance(){
if(NULL === self::$SingletonFoo) {
throw new NotInstantiatedException();
}
return self::$SingletonFoo;
}
}
Don't use Singleton, use Resources Manager (or Service Container, or DI Container):
class ResourceManager
{
protected static $resource;
public static function setResource($resource)
{
if (!empty(self::$resource)) //resource should not be overwritten
{
if ($resource!=self::$resource) return false;
else return true;
}
self::$resource = $resource;
return true;
}
public static function getResource()
{
return self::$resource;
}
}
Resource Manager allows you to set any custom classes for unit-testing (like dependency injection), you can just get needed resources without requesting them in constructor (I like DI, but sometimes it's just more handy to use empty constructors).
Ready-to-use variant: http://symfony.com/doc/current/book/service_container.html (I don't like to move logic from code to configs, but in stand-alone module it looks acceptable).
I want to stop object creation by the user of class "OzoneRequest" and "OzoneResponse"in PHP . Only one object is created at OzoneApplication's constructor. How I'll do this? May be you understand my question
I do not want creation of object by the user Only I create an object that only one object exist. If user want to create object then this will not be performed... this will give an error......
class OzoneRequest
{
private static $instance = null;
private function __construct() { }
private function __clone() { }
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new OzoneRequest();
}
return self::$instance;
}
}
class OzoneApplication
{
protected $req;
public function __construct()
{
$this->req = OzoneRequest::getInstance();
}
}
Make a private constructor, then call this from a static method within the class to create your one object. Also, lookup the singleton design pattern.
That would be the UseCase for a Singleton.
However, I do not see the point in restricting the User (read: the developer) to not create a Request or Response object if he wants to. Even if conceptually there is only one Request object (which is arguable; what if I need to dispatch multiple Requests against a remote service), the question is: why do you forbid a developer to change your code? I am a grown-up. If I want to break your code, let me break it.
Also note that the Singleton pattern is widely regarded an Anti-Pattern nowadays.
How will I use an instance of an object that is initially loaded throughout the whole site?
I want $myinstance to be used everywhere.
$myinstance = new TestClass();
Thanks!
What you are looking for is called the singleton pattern.
If you are deeply into OOP architecture, and want to do things like Unit Testing in the future: Singletons are regarded as an imperfect approach and not "pure" in the sense of OOP. I asked a question on the issue once, and got pretty good results with other, better patterns. A lot of good reading.
If you just want to get started with something, and need your DB class available everywhere, just use a Singleton.
You just need to declare your variable in global scope (for example, in the begginning of your whole code), and when you want to use it inside a function, use the "global" statement. See http://php.net/global.
I'm not 100% sure I got what you want to do... but I'll try to answer anyway.
I think you can save it to a session variable, using the serialize/unserialize functions to save/retrieve your class instance. Probably you'd code TestClass as a singleton, but that really depends on what you're trying to do.
For instance:
if (!isset($_SESSION["my_class_session_var"])) // The user is visiting for the 1st time
{
$test = new TestClass();
// Do whatever you need to initialise $test...
$_SESSION["my_class_session_var"] = serialize($test);
}
else // Session variable already set. Retrieve it
{
$test = unserialize($_SESSION['my_class_session_var']);
}
There is a design pattern called Singleton. In short:
Change __construct and __clone to private, so calling new TestClass() will end up with Error!
Now make a class that will create new instance of your object or return existing one...
Example:
abstract class Singleton
{
final private function __construct()
{
if(isset(static::$instance)) {
throw new Exception(get_called_class()." already exists.");
}
}
final private function __clone()
{
throw new Exception(get_called_class()." cannot be cloned.");
}
final public static function instance()
{
return isset(static::$instance) ? static::$instance : static::$instance = new static;
}
}
Then try to extend this class and define static $instance variable
class TestClass extends Singleton
{
static protected $instance;
// ...
}
Now try this:
echo get_class($myinstance = TestClass::instance();
echo get_class($mysecondinstance = TestClass::instance());
Done