I would like to make a simple ORM in PHP for standard CRUD interaction with my db, I also want make it work in php5 for legacy compatibility.
I've written some classes to do this and it works, but not completely as I would.
This is the idea. I have an abstrac class called ModelBase which has a property (tableName) and some metods like select, insert, update and delete, plus has an abstract method, getData, that will be implemented by the classes that will be implement ModelBase and should return object of correct type.
So, for example, I could have a class Users which implements ModelBase and one another class UserData which is the model with the property.
Here is the code:
abstract class ModelBase{
private $tableName;
public function __construct($tableName) {
$this->tableName = $tableName;
}
public function select{
// make select query to db and retreive data
// ...
$resData = [];
while($dataRow = mysqli_fetch_array($res, MYSQLI_ASSOC)) {
$resData[] = $this->getObjectData($dataRow); // implemented in child class
}
return $resData;
}
public function insert(){ /* ... */}
public function update(){ /* ... */}
public function delete(){ /* ... */}
abstract function getObjectData($data); // maps the results
}
class UserData {
public $id;
public $name;
public $surname;
public $email;
// other fields
public function __construct() {}
}
class User implements ModelBase {
private $tableName = 'users';
public function __construct() {
parent::__construct($this->tableName);
}
public function getObjectData($dataRow) {
$o = new UserData ();
// mapping dataRow to object fields
$o->id = $dataRow['ID'];
// ....
return $o;
}
}
So I use my classes in this way:
$users = new Users();
$u = users->select();
$firstUser = $u[0]; // I get my user if exists
In $firstUser I'll get my object with property and correct data but I would like to have that also my IDE (vsCode in this case) would recognize the object type in order to suggest the correct properties. So if I write $firstUser-> I would like to see field suggestions (id, name, surname, ...) from UserData and for other xyzData classes as well.
What I should do to improve my classes in order to see property suggestions when I use my objects, also in php5?
Solution for PHP 8, tested on PHPStorm.
<?php
class Base {
/**
* #return static[]
*/
public function select() : array {
return [new self];
}
public function selectFirst() : static {
return $this->select()[0];
}
}
class User extends Base {
public ?string $userName = null;
}
#detects the current class via () : static
(new User)->selectFirst()->userName;
#detects the current class via #return static[]
(new User)->select()[0]->userName;
In line solution for PHP 5, define the variable directly with this comment
/** #var $a User */
$a->userName;
There is no benefit of supporting old PHP 5. You lose so mutch clean code and modern approach when supporting old php versions.
But when you have to, then go with the inline solution.
Not tested and not so clean for PHP 5:
class User extends Base {
public ?string $userName = null;
/**
* #return User[]
*/
public function select() : array {
return parent::select();
}
}
here is my situation :
I have a class that is inherited by a dozen of others, in this class I have a copy method which returns a copy of itself.
I can use this method in the inheriting class but, obviously, the method always return an instance of the super class, not the one which inherit from it.
I would like my copy method to return an instance of the ihneriting class.
BaseEntity.php :
class BaseEntity
{
protected $id;
protected $name;
protected $active;
protected $deleted;
// ...
public function copy()
{
$copy = new BaseEntity();
$copy->id = $this->id;
$copy->name = $this->name;
$copy->active = $this->active;
$copy->deleted = $this->deleted;
return $copy;
}
}
User.php :
class User extends BaseEntity
{
// ...
// Properties are the same as BaseEntity, there is just more methods.
}
One more way to achieve what you want:
<?php
class BaseEntity
{
protected $id;
public function copy()
{
$classname = get_class($this);
$copy = new $classname;
return $copy;
}
}
class Test extends BaseEntity
{
}
$test = new Test;
$item = $test->copy();
var_dump($item); // object(Test)
I see two ways of doing this:
using clone - it will make a shallow copy of your object
using static for creating a new object
<?php
class BaseEntity {
public function copy() {
return new static;
}
}
class User extends BaseEntity {
}
$user = new User;
var_dump($user->copy());
Result of this code: https://3v4l.org/2naQI
I want to put my Zend Model as Singleton, so I have done this:
class Social_Model_DbTable_Dossier extends Zend_Db_Table_Abstract {
private static $_instance;
public static function GetInstance() {
if (!self::$_instance instanceof self) {
self::$_instance = new self();
}
return self::$_instance;
}
private function __construct() {
// put normal constructor code.
// it will only ever be called once
}}
I instantiate my model like so:
$dossiercasModel = Social_Model_DbTable_Dossier::GetInstance();
but this erreur is occured:
Fatal error: Access level to Social_Model_DbTable_Dossier::__construct() must be public (as in class Zend_Db_Table_Abstract)
when I put the constructor of the Model as public it works fine but this is inconsistent with the notion of singleton!
In the past I have gotten arround having to do this by creating a table broker that would serve up cached table instances,
kind of a multiton.
a simple example
class My_TableManager{
protected static $_instance;
protected $_tableCache = array();
protected function __construct(){
}
public static function getInstance(){
if (!isset(self::$_instance)) self::$_instance = new self();
}
public function getTable($tableName){
if (!array_key_exists($tableName, $this->_tableCache)){
// you can do fun stuff here like name inflection
// Im assuming that tables will be suffixed with _Table
$tableClass = "My_".$tableName."_Table";
$this->_tableCache[$tableName] = new $tableClass();
}
return $this->_tableCache[$tableName];
}
public static function get($tableName){
return self::getInstance()->getTable($tableName);
}
}
To use to get an instance of My_User_Table you would could:
$table = My_TableManager::get("My_User");
or
$table = My_TableManager::getInstnace()->getTable("My_Table");
I am writing some tests for a Magento module, using Ivan Chepurnyi's extension, and I'm having trouble using the mock objects.
Here is the class:
<?php
class Namespace_Module_Block_Class extends Mage_Core_Block_Template
{
private $_salesCollection;
public function __construct()
{
$this->_salesCollection = Mage::getModel('module/classA')->getCollection()
->addFieldToFilter('id', $this->_getId());
}
public function _getId()
{
return Mage::getModel('module/classB')->getId();//session params
}
public function getSalesTotalNumber()
{
return $this->_salesCollection->count();
}
}
The method I'm trying to test is getSalesTotalNumber().
And here is the test:
<?php
class Namespace_Module_Test_Block_Class extends EcomDev_PHPUnit_Test_Case
{
private $_mock;
public function setUp()
{
$this->_mock = $this->getMock('Namespace_Module_Block_Class',
array('_getId')
);
$this->_mock->expects($this->any())
->method('_getId')
->will($this->returnValue(1024));
parent::setUp();
}
/**
* #test
* #loadFixture
* #loadExpectation
*/
public function testSalesTotalNumber()
{
$actual = $this->_mock->getSalesTotalValue();
$expected = $this->_getExpectations()->getSalesTotalNumber();
$this->assertEquals($expected, $actual);
}
}
As you can see, what I want to do is overwrite the _getId() method so that it returns an id which match the id in the fixture and so load the collection. But it doesn't work :-(.
In my test, if I echo $this->_mock->_getId() it returns the correct Id (1024). But in the __construct() of my class $this->_getId() returns null, which is the expected value during testing (I mean, during testing there is no session, so it can't get the object's Id as I store it in a session variable). So the _getId() method isn't mocked by my test case.
Any help will be highly appreciated.
So my problem was not in the mock/test but in the class.
I have moved the content of __construct() into a protected method which returns the collection object. That's how my class looks like now:
<?php
class Namespace_Module_Block_Class extends Mage_Core_Block_Template
{
private $_salesCollection;
protected function _getAffiliateSales()
{
if (is_null($this->_salesCollection)) {
$affiliateId = $this->_getId();
$this->_salesCollection = Mage::getModel('module/classA')
->addFieldToFilter('id', $affiliateId);
}
return $this->_salesCollection;
}
public function _getId()
{
return Mage::getModel('module/classB')->getId();//session params
}
public function getSalesTotalNumber()
{
return $this->_getAffiliateSales()->count();
}
}
How would one create a Singleton class using PHP5 classes?
/**
* Singleton class
*
*/
final class UserFactory
{
private static $inst = null;
// Prevent cloning and de-serializing
private function __clone(){}
private function __wakeup(){}
/**
* Call this method to get singleton
*
* #return UserFactory
*/
public static function Instance()
{
if ($inst === null) {
$inst = new UserFactory();
}
return $inst;
}
/**
* Private ctor so nobody else can instantiate it
*
*/
private function __construct()
{
}
}
To use:
$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();
$fact == $fact2;
But:
$fact = new UserFactory()
Throws an error.
See http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static to understand static variable scopes and why setting static $inst = null; works.
Unfortunately Inwdr's answer breaks when there are multiple subclasses.
Here is a correct inheritable Singleton base class.
class Singleton
{
private static $instances = array();
protected function __construct() {}
protected function __clone() {}
public function __wakeup()
{
throw new Exception("Cannot unserialize singleton");
}
public static function getInstance()
{
$cls = get_called_class(); // late-static-bound class name
if (!isset(self::$instances[$cls])) {
self::$instances[$cls] = new static;
}
return self::$instances[$cls];
}
}
Test code:
class Foo extends Singleton {}
class Bar extends Singleton {}
echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";
PHP 5.3 allows the creation of an inheritable Singleton class via late static binding:
class Singleton
{
protected static $instance = null;
protected function __construct()
{
//Thou shalt not construct that which is unconstructable!
}
protected function __clone()
{
//Me not like clones! Me smash clones!
}
public static function getInstance()
{
if (!isset(static::$instance)) {
static::$instance = new static;
}
return static::$instance;
}
}
This solves the problem, that prior to PHP 5.3 any class that extended a Singleton would produce an instance of its parent class instead of its own.
Now you can do:
class Foobar extends Singleton {};
$foo = Foobar::getInstance();
And $foo will be an instance of Foobar instead of an instance of Singleton.
The Real One and Modern way to make Singleton Pattern is:
<?php
/**
* Singleton Pattern.
*
* Modern implementation.
*/
class Singleton
{
/**
* Call this method to get singleton
*/
public static function instance()
{
static $instance = false;
if( $instance === false )
{
// Late static binding (PHP 5.3+)
$instance = new static();
}
return $instance;
}
/**
* Make constructor private, so nobody can call "new Class".
*/
private function __construct() {}
/**
* Make clone magic method private, so nobody can clone instance.
*/
private function __clone() {}
/**
* Make sleep magic method private, so nobody can serialize instance.
*/
private function __sleep() {}
/**
* Make wakeup magic method private, so nobody can unserialize instance.
*/
private function __wakeup() {}
}
So now you can use it like.
<?php
/**
* Database.
*
* Inherited from Singleton, so it's now got singleton behavior.
*/
class Database extends Singleton {
protected $label;
/**
* Example of that singleton is working correctly.
*/
public function setLabel($label)
{
$this->label = $label;
}
public function getLabel()
{
return $this->label;
}
}
// create first instance
$database = Database::instance();
$database->setLabel('Abraham');
echo $database->getLabel() . PHP_EOL;
// now try to create other instance as well
$other_db = Database::instance();
echo $other_db->getLabel() . PHP_EOL; // Abraham
$other_db->setLabel('Priler');
echo $database->getLabel() . PHP_EOL; // Priler
echo $other_db->getLabel() . PHP_EOL; // Priler
As you see this realization is lot more flexible.
You probably should add a private __clone() method to disallow cloning of an instance.
private function __clone() {}
If you don't include this method the following gets possible
$inst1=UserFactory::Instance(); // to stick with the example provided above
$inst2=clone $inst1;
now $inst1 !== $inst2 - they are not the same instance any more.
<?php
/**
* Singleton patter in php
**/
trait SingletonTrait {
protected static $inst = null;
/**
* call this method to get instance
**/
public static function getInstance(){
if (static::$inst === null){
static::$inst = new static();
}
return static::$inst;
}
/**
* protected to prevent clonning
**/
protected function __clone(){
}
/**
* protected so no one else can instance it
**/
protected function __construct(){
}
}
to use:
/**
* example of class definitions using SingletonTrait
*/
class DBFactory {
/**
* we are adding the trait here
**/
use SingletonTrait;
/**
* This class will have a single db connection as an example
**/
protected $db;
/**
* as an example we will create a PDO connection
**/
protected function __construct(){
$this->db =
new PDO('mysql:dbname=foodb;port=3305;host=127.0.0.1','foouser','foopass');
}
}
class DBFactoryChild extends DBFactory {
/**
* we repeating the inst so that it will differentiate it
* from UserFactory singleton
**/
protected static $inst = null;
}
/**
* example of instanciating the classes
*/
$uf0 = DBFactoryChild::getInstance();
var_dump($uf0);
$uf1 = DBFactory::getInstance();
var_dump($uf1);
echo $uf0 === $uf1;
respose:
object(DBFactoryChild)#1 (0) {
}
object(DBFactory)#2 (0) {
}
If you are using PHP 5.4: trait its an option, so you don't have to waste the inheritance hierarchy in order to have the Singleton pattern
and also notice that whether you use traits or extends Singleton class
one loose end was to create singleton of child classes if you dont add the following line of code:
protected static $inst = null;
in the child class
the unexpected result will be:
object(DBFactoryChild)#1 (0) {
}
object(DBFactoryChild)#1 (0) {
}
protected static $_instance;
public static function getInstance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
This code can apply for any class without caring about its class name.
Supports Multiple Objects with 1 line per class:
This method will enforce singletons on any class you wish, al you have to do is add 1 method to the class you wish to make a singleton and this will do it for you.
This also stores objects in a "SingleTonBase" class so you can debug all your objects that you have used in your system by recursing the SingleTonBase objects.
Create a file called SingletonBase.php and include it in root of your script!
The code is
abstract class SingletonBase
{
private static $storage = array();
public static function Singleton($class)
{
if(in_array($class,self::$storage))
{
return self::$storage[$class];
}
return self::$storage[$class] = new $class();
}
public static function storage()
{
return self::$storage;
}
}
Then for any class you want to make a singleton just add this small single method.
public static function Singleton()
{
return SingletonBase::Singleton(get_class());
}
Here is a small example:
include 'libraries/SingletonBase.resource.php';
class Database
{
//Add that singleton function.
public static function Singleton()
{
return SingletonBase::Singleton(get_class());
}
public function run()
{
echo 'running...';
}
}
$Database = Database::Singleton();
$Database->run();
And you can just add this singleton function in any class you have and it will only create 1 instance per class.
NOTE: You should always make the __construct private to eliminate the use of new Class(); instantiations.
class Database{
//variable to hold db connection
private $db;
//note we used static variable,beacuse an instance cannot be used to refer this
public static $instance;
//note constructor is private so that classcannot be instantiated
private function __construct(){
//code connect to database
}
//to prevent loop hole in PHP so that the class cannot be cloned
private function __clone() {}
//used static function so that, this can be called from other classes
public static function getInstance(){
if( !(self::$instance instanceof self) ){
self::$instance = new self();
}
return self::$instance;
}
public function query($sql){
//code to run the query
}
}
Access the method getInstance using
$db = Singleton::getInstance();
$db->query();
You don't really need to use Singleton pattern because it's considered to be an antipattern. Basically there is a lot of reasons to not to implement this pattern at all. Read this to start with: Best practice on PHP singleton classes.
If after all you still think you need to use Singleton pattern then we could write a class that will allow us to get Singleton functionality by extending our SingletonClassVendor abstract class.
This is what I came with to solve this problem.
<?php
namespace wl;
/**
* #author DevWL
* #dosc allows only one instance for each extending class.
* it acts a litle bit as registry from the SingletonClassVendor abstract class point of view
* but it provides a valid singleton behaviour for its children classes
* Be aware, the singleton pattern is consider to be an anti-pattern
* mostly because it can be hard to debug and it comes with some limitations.
* In most cases you do not need to use singleton pattern
* so take a longer moment to think about it before you use it.
*/
abstract class SingletonClassVendor
{
/**
* holds an single instance of the child class
*
* #var array of objects
*/
protected static $instance = [];
/**
* #desc provides a single slot to hold an instance interchanble between all child classes.
* #return object
*/
public static final function getInstance(){
$class = get_called_class(); // or get_class(new static());
if(!isset(self::$instance[$class]) || !self::$instance[$class] instanceof $class){
self::$instance[$class] = new static(); // create and instance of child class which extends Singleton super class
echo "new ". $class . PHP_EOL; // remove this line after testing
return self::$instance[$class]; // remove this line after testing
}
echo "old ". $class . PHP_EOL; // remove this line after testing
return static::$instance[$class];
}
/**
* Make constructor abstract to force protected implementation of the __constructor() method, so that nobody can call directly "new Class()".
*/
abstract protected function __construct();
/**
* Make clone magic method private, so nobody can clone instance.
*/
private function __clone() {}
/**
* Make sleep magic method private, so nobody can serialize instance.
*/
private function __sleep() {}
/**
* Make wakeup magic method private, so nobody can unserialize instance.
*/
private function __wakeup() {}
}
Use example:
/**
* EXAMPLE
*/
/**
* #example 1 - Database class by extending SingletonClassVendor abstract class becomes fully functional singleton
* __constructor must be set to protected becaouse:
* 1 to allow instansiation from parent class
* 2 to prevent direct instanciation of object with "new" keword.
* 3 to meet requierments of SingletonClassVendor abstract class
*/
class Database extends SingletonClassVendor
{
public $type = "SomeClass";
protected function __construct(){
echo "DDDDDDDDD". PHP_EOL; // remove this line after testing
}
}
/**
* #example 2 - Config ...
*/
class Config extends SingletonClassVendor
{
public $name = "Config";
protected function __construct(){
echo "CCCCCCCCCC" . PHP_EOL; // remove this line after testing
}
}
Just to prove that it works as expected:
/**
* TESTING
*/
$bd1 = Database::getInstance(); // new
$bd2 = Database::getInstance(); // old
$bd3 = Config::getInstance(); // new
$bd4 = Config::getInstance(); // old
$bd5 = Config::getInstance(); // old
$bd6 = Database::getInstance(); // old
$bd7 = Database::getInstance(); // old
$bd8 = Config::getInstance(); // old
echo PHP_EOL."COMPARE ALL DATABASE INSTANCES".PHP_EOL;
var_dump($bd1);
echo '$bd1 === $bd2' . ($bd1 === $bd2)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd2 === $bd6' . ($bd2 === $bd6)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd6 === $bd7' . ($bd6 === $bd7)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo PHP_EOL;
echo PHP_EOL."COMPARE ALL CONFIG INSTANCES". PHP_EOL;
var_dump($bd3);
echo '$bd3 === $bd4' . ($bd3 === $bd4)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd4 === $bd5' . ($bd4 === $bd5)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd5 === $bd8' . ($bd5 === $bd8)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
All this complexity ("late static binding" ... harumph) is, to me, simply a sign of PHP's broken object/class model. If class objects were first-class objects (see Python), then "$_instance" would be a class instance variable -- a member of the class object, as opposed to a member/property of its instances, and also as opposed to shared by its descendants. In the Smalltalk world, this is the difference between a "class variable" and a "class instance variable".
In PHP, it looks to me as though we need to take to heart the guidance that patterns are a guide towards writing code -- we might perhaps think about a Singleton template, but trying to write code that inherits from an actual "Singleton" class looks misguided for PHP (though I supposed some enterprising soul could create a suitable SVN keyword).
I will continue to just code each singleton separately, using a shared template.
Notice that I'm absolutely staying OUT of the singletons-are-evil discussion, life is too short.
I know this is probably going to cause an unnecessary flame war, but I can see how you might want more than one database connection, so I would concede the point that singleton might not be the best solution for that... however, there are other uses of the singleton pattern that I find extremely useful.
Here's an example: I decided to roll my own MVC and templating engine because I wanted something really lightweight. However, the data that I want to display contains a lot of special math characters such as ≥ and μ and what have you... The data is stored as the actual UTF-8 character in my database rather than pre-HTML-encoded because my app can deliver other formats such as PDF and CSV in addition to HTML. The appropriate place to format for HTML is inside the template ("view" if you will) that is responsible for rendering that page section (snippet). I want to convert them to their appropriate HTML entities, but PHPs get_html_translation_table() function is not super fast. It makes better sense to retrieve the data one time and store as an array, making it available for all to use. Here's a sample I knocked together to test the speed. Presumably, this would work regardless of whether the other methods you use (after getting the instance) were static or not.
class EncodeHTMLEntities {
private static $instance = null;//stores the instance of self
private $r = null;//array of chars elligalbe for replacement
private function __clone(){
}//disable cloning, no reason to clone
private function __construct()
{
$allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
$specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
$this->r = array_diff($allEntities, $specialEntities);
}
public static function replace($string)
{
if(!(self::$instance instanceof self) ){
self::$instance = new self();
}
return strtr($string, self::$instance->r);
}
}
//test one million encodings of a string
$start = microtime(true);
for($x=0; $x<1000000; $x++){
$dump = EncodeHTMLEntities::replace("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)");
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds using singleton\n";
//now repeat the same without using singleton
$start = microtime(true);
for($x=0; $x<1000000; $x++){
$allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
$specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
$r = array_diff($allEntities, $specialEntities);
$dump = strtr("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)", $r);
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds without using singleton";
Basically, I saw typical results like this:
php test.php
Run time: 27.842966794968 seconds using singleton
Run time: 237.78191494942 seconds without using singleton
So while I'm certainly no expert, I don't see a more convenient and reliable way to reduce the overhead of slow calls for some kind of data, while making it super simple (single line of code to do what you need). Granted my example only has one useful method, and therefore is no better than a globally defined function, but as soon as you have two methods, you're going to want to group them together, right? Am I way off base?
Also, I prefer examples that actually DO something, since sometimes it's hard to visualise when an example includes statements like "//do something useful here" which I see all the time when searching for tutorials.
Anyway, I'd love any feedback or comments on why using a singleton for this type of thing is detrimental (or overly complicated).
This article covers topic quite extensively:
http://www.phptherightway.com/pages/Design-Patterns.html#singleton
Note the following:
The constructor __construct() is declared as protected to prevent creating a new instance outside of the class via the new operator.
The magic method __clone() is declared as private to prevent cloning of an instance of the class via the clone operator.
The magic method __wakeup() is declared as private to prevent unserializing of an instance of the class via the global function
unserialize().
A new instance is created via late static binding in the static creation method getInstance() with the keyword static. This
allows the subclassing of the class Singleton in the example.
I have written long back thought to share here
class SingletonDesignPattern {
//just for demo there will be only one instance
private static $instanceCount =0;
//create the private instance variable
private static $myInstance=null;
//make constructor private so no one create object using new Keyword
private function __construct(){}
//no one clone the object
private function __clone(){}
//avoid serialazation
public function __wakeup(){}
//ony one way to create object
public static function getInstance(){
if(self::$myInstance==null){
self::$myInstance=new SingletonDesignPattern();
self::$instanceCount++;
}
return self::$myInstance;
}
public static function getInstanceCount(){
return self::$instanceCount;
}
}
//now lets play with singleton design pattern
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
echo "number of instances: ".SingletonDesignPattern::getInstanceCount();
I agree with the first answer but I would also declare the class as final so that it cannot be extended as extending a singleton violates the singleton pattern. Also the instance variable should be private so that it cannot be accessed directly. Also make the __clone method private so that you cannot clone the singleton object.
Below is some example code.
/**
* Singleton class
*
*/
final class UserFactory
{
private static $_instance = null;
/**
* Private constructor
*
*/
private function __construct() {}
/**
* Private clone method
*
*/
private function __clone() {}
/**
* Call this method to get singleton
*
* #return UserFactory
*/
public static function getInstance()
{
if (self::$_instance === null) {
self::$_instance = new UserFactory();
}
return self::$_instance;
}
}
Example Usage
$user_factory = UserFactory::getInstance();
What this stops you from doing (which would violate the singleton pattern..
YOU CANNOT DO THIS!
$user_factory = UserFactory::$_instance;
class SecondUserFactory extends UserFactory { }
This should be the right way of Singleton.
class Singleton {
private static $instance;
private $count = 0;
protected function __construct(){
}
public static function singleton(){
if (!isset(self::$instance)) {
self::$instance = new Singleton;
}
return self::$instance;
}
public function increment()
{
return $this->count++;
}
protected function __clone(){
}
protected function __wakeup(){
}
}
I liked #jose-segura method of using traits but didn't like the need to define a static variable on sub-classes. Below is a solution that avoids it by caching the instances in a static local variable to the factory method indexed by class name:
<?php
trait Singleton {
# Single point of entry for creating a new instance. For a given
# class always returns the same instance.
public static function instance(){
static $instances = array();
$class = get_called_class();
if( !isset($instances[$class]) ) $instances[$class] = new $class();
return $instances[$class];
}
# Kill traditional methods of creating new instances
protected function __clone() {}
protected function __construct() {}
}
Usage is the same as #jose-segura only no need for the static variable in sub-classes.
Database class that checks if there is any existing database instance it will return previous instance.
class Database {
public static $instance;
public static function getInstance(){
if(!isset(Database::$instance) ) {
Database::$instance = new Database();
}
return Database::$instance;
}
private function __cunstruct() {
/* private and cant create multiple objects */
}
public function getQuery(){
return "Test Query Data";
}
}
$dbObj = Database::getInstance();
$dbObj2 = Database::getInstance();
var_dump($dbObj);
var_dump($dbObj2);
/*
After execution you will get following output:
object(Database)[1]
object(Database)[1]
*/
Ref http://www.phptechi.com/php-singleton-design-patterns-example.html
This is the example of create singleton on Database class
design patterns
1) singleton
class Database{
public static $instance;
public static function getInstance(){
if(!isset(Database::$instance)){
Database::$instance=new Database();
return Database::$instance;
}
}
$db=Database::getInstance();
$db2=Database::getInstance();
$db3=Database::getInstance();
var_dump($db);
var_dump($db2);
var_dump($db3);
then out put is --
object(Database)[1]
object(Database)[1]
object(Database)[1]
use only single instance not create 3 instance
Quick example:
final class Singleton
{
private static $instance = null;
private function __construct(){}
private function __clone(){}
private function __wakeup(){}
public static function get_instance()
{
if ( static::$instance === null ) {
static::$instance = new static();
}
return static::$instance;
}
}
Hope help.
The above answers are ok, But I'll add more.
Whoever come here in 2021, I'll show another example of using Singleton Pattern class as a trait and Re-use this in any class.
<?php
namespace Akash;
trait Singleton
{
/**
* Singleton Instance
*
* #var Singleton
*/
private static $instance;
/**
* Private Constructor
*
* We can't use the constructor to create an instance of the class
*
* #return void
*/
private function __construct()
{
// Don't do anything, we don't want to be initialized
}
/**
* Get the singleton instance
*
* #return Singleton
*/
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Private clone method to prevent cloning of the instance of the
* Singleton instance.
*
* #return void
*/
private function __clone()
{
// Don't do anything, we don't want to be cloned
}
/**
* Private unserialize method to prevent unserializing of the Singleton
* instance.
*
* #return void
*/
private function __wakeup()
{
// Don't do anything, we don't want to be unserialized
}
}
So, use it like in any class easily. Suppose, we want to implement Singleton pattern in UserSeeder class.
<?php
class UserSeeder
{
use Singleton;
/**
* Seed Users
*
* #return void
*/
public function seed()
{
echo 'Seeding...';
}
}
Here's my example that provides ability to call as $var = new Singleton() and also creating 3 variables to test if it creates new object:
class Singleton{
private static $data;
function __construct(){
if ($this::$data == null){
$this->makeSingleton();
}
echo "<br/>".$this::$data;
}
private function makeSingleton(){
$this::$data = rand(0, 100);
}
public function change($new_val){
$this::$data = $new_val;
}
public function printme(){
echo "<br/>".$this::$data;
}
}
$a = new Singleton();
$b = new Singleton();
$c = new Singleton();
$a->change(-2);
$a->printme();
$b->printme();
$d = new Singleton();
$d->printme();