Below is a very basic example of the trouble I am having.
Now why must I use $session = new Session(); in the database.class.php file when in my system the files are included in a way that it would be visible already.
In other words I cannot call $session = new Session(); outside of any other classes, to make it work in other classes I have to call create a new objectof the session class in every class I want to use it in, how can I avoid this and make it work without doing that?
// Session.class.php
class Session{
public function __construct()
{
session_start();
}
public function set($name, $value)
{
$_SESSION[$name] = $value;
}
}
...
// Database.class.php
class Database{
public static function mysql_query_2($query)
{
if ($session->get('user_role') == 10){
$_SESSION['queries']++;
}
return mysql_query($query);
}
}
First and foremost, your Session class should be a singleton - the reason is that multiple calls to session_start() will get you nothing but problems (session id gets regenerated)
So...
/**
* Session singleton class
*/
class Session
{
// prevents object instanciation ($obj = new Session())
protected function __construct() {
session_start();
}
// prevents object cloning
protected function __clone() {}
public static function getInstance()
{
static $instance = null;
if ($instance == null)
$instance = new Session();
return $instance;
}
// rest of the code
}
To use it you simply call:
$sess = Session::getInstance();
$sess->doSomething();
or simply
Session::getInstance()->doSomething();
Anywhere you need to use the session class.
Update:
- I see you probably don't grasp the concept of singletons yet, so here's a proper wikipedia link 8)
If I understand your problem correctly, one solution to your problem is to use a Singleton.
final class Singleton {
protected static $_instance;
// Singleton can't be constructed or cloned
protected function __construct(){ }
protected function __clone() { }
// Create an instance if necessary and return an instance.
public static function getInstance(){
if( self::$_instance === NULL ) {
session_start();
self::$_instance = new self();
}
return self::$_instance;
}
public function set($name, $value){
$_SESSION[$name] = $value;
}
}
In index.php you would have:
$session = Session::getInstance();
$session->get();
Then in your Database class you would have:
// Database.class.php
class Database{
public static function mysql_query_2($query)
{
if (Session::getInstance()->get('user_role') == 10){
$_SESSION['queries']++;
}
return mysql_query($query);
}
}
You would only ever create one instance of the Session class (which is what I think your looking for). Then when you need the Session class somewhere else (ie your Database class) you just call Session::getInstance() again. There is only one instance of Session ever created and you can use it globally across your script.
Related
so I have some classes which only need to be initialized once to fill them with data. Now I want to access them seperately with AJAX but without having them initialized again. I read about singleton in PHP, but I wonder if it's possible to have the same instance of the class in multiple scripts, which can be called seperatedly. Example:
<?php
class Example {
private $instance;
private $A;
public function __construct() {}
public function __clone() {}
public function singleton() {
if (self::$instance === null) {
self::$instance = new Example;
return self::$instance;
}
public function setA($val) {
$this->A = $val;
}
public function getA() {
return $this->A;
}
}
?>
script_a.php:
<?php
include_once('example.class.php');
Example::singleton()->setA(10);
?>
script_b.php:
<?php
include_once('example.class.php');
echo Example::singleton()->getA();
// Would this output 10?
?>
I also read that static functions will be deleted from memory at the end of the script execution, does this also apply for singleton? If so, is there a way to make the above happen?
Singleton does not preserve state over multiple requests - you should use sessions for that. Once you use session then there is no point in using singleton pattern.
A very simple solution:
script_a.php:
<?php
session_start();
$_SESSION['A'] = 10;
?>
script_b.php:
<?php
session_start();
if(isset($_SESSION['A'])) {
echo $_SESSION['A'];
// do the rest of processing
}
?>
Sessions are ok if not sharing data between multiple clients (good for single client - multiple requests).
Another way of preserving state over multiple requests that is shared across clients is caching (you can cache scalars, arrays, db connections or objects) and for that check more on this link
No, the Singleton pattern does not do anything cross-script. Singletons in PHP are mainly useful to get either a pre-initialized or self-initializing instance of a class only once instead of either passing objects through constructors or creating potentially dozens of identical copies of a class when only one is really needed.
eg:
class MySingleton {
private static myInstance = NULL;
private function __construct() {}
public static getInstance($arg) {
if( is_null(self::myInstance) ) {
echo "INIT HERE!";
self::myInstance = new MySingleton();
}
return self::myInstance();
}
}
class myClass {
public $single;
public function __construct() {
$this->single = MySingleton::getInstance();
}
}
$one = new myClass(); // INIT HERE is echoed
$two = new myClass();
$one->single->someVar = 'foo';
echo $two->single->someVar; // foo
$two->single->someVar = 'bar';
echo $one->single->someVar; // bar
Essentially most people in the PHP world use singletons for their database classes so that they only ever have to open a single connection to the database per script. There is some contention among the old farts that there are problems inherent in this approach where prepared statements can interfere with each other [which is true] and using SQL variables can be problematic. [also true] But so long as you're aware that you must fully complete a SQL statement before calling another object method that uses the singleton then you should be fine.
You can use APC cache for that:
class Singleton {
private $a;
private static $key = 'my_unique_singleton_key';
// this functions must be private for a real Singletone
private function __construct() {}
private function __clone() {}
private function __wakeup() {}
// automatically save object during the script shutdown
private function __destruct() {
apc_add(self::$key, self::getInstance());
}
public static function getInstance() {
static $instance;
if (null === $instance) {
if (apc_exists(self::$key)) {
$instance = apc_fetch(self::$key);
} else {
$instance = new self();
apc_add(self::$key, $instance);
}
}
return $instance;
}
public function setA($val) {
$this->a = $val;
}
public function getA() {
return $this->a;
}
}
This can be used simple as that:
echo Singleton::getInstance()->getA();
I'm using PDT and Aptana on Eclipse Indigo with PHP 5.3 and I want to create a singleton in a class.
By singleton, I mean I want to just have one instance of that object, and for other objects or classes to get that single instance via a function that returns that object (so this would mean I'm trying to create an object within the class that defines that object, ie: creating objA within the class objA)
I understand you can't just go a head and do this:
public $object = new Object();
with in a class definition, you have to define it in the constructor.
How can I go ahead and do this? I'm coming from Java, so it could be I'm confusing some basic stuff. Any help is greatly appreciated. Here's the code:
<?php
class Fetcher{
private static $fetcher = new Fetcher(); //this is where I get the unexpected "new" error
static function getFetcherInstance(){
return $this->$fetcher;
}
}
?>
Solved! Thanks for all the help guys!
try this:
<?php
class myclass{
private static $_instance = null;
public static function getInstance() {
if (self::$_instance === null) {
self::$_instance = new myclass();
}
return self::$_instance;
}
}
?>
and call it with:
<?php
$obj = myclass::getInstace();
?>
You cannot assign a class property in PHP like that. It must be a scalar, or array value, or the property must be set in a method call.
protected static $fetcher;
static function getFetcherInstance(){
if (!self::$fetcher) {
self::$fetcher = new Fetcher();
}
return self::$fetcher;
}
Also, notice that I did not use $this->, as that only works for object instances. To work with static values you need to use self:: when working within the class scope.
You might want to just read common design patterns on the php site. There are pretty good examples with good documentation:
http://www.php.net/manual/en/language.oop5.patterns.php
Else, a singleton is simply a method that returns one single instance of itself:
class MySingletonClass {
private static $mySingleton;
public function getInstance(){
if(MySingletonClass::$mySingleton == NULL){
MySingletonClass::$mySingleton = new MySingletonClass();
}
return MySingletonClass::$mySingleton;
}
}
Building on #periklis answer you might want separate singletons for different application scopes. For example, lets say you want a singleton of a database connection - fine. But what if you have TWO databases you need to connect too?
<?php
class Singleton
{
private static $instances = array();
public static function getInstance($name = 'default')
{
if ( ! isset(static::$instances[$name]))
{
static::$instances[$name] = new static();
}
return static::$instances[$name];
}
}
Class DB extends Singleton {}
$db_one = DB::getInstance('mysql');
$db_two = DB::getInstance('pgsql');
Alse define __clone method
class Fetcher {
protected static $instance;
private function __construct() {
/* something */
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new Fetcher();
}
return self::$instance;
}
private function __clone() {
/* if we want real singleton :) */
trigger_error('Cannot clone', E_USER_ERROR);
}
}
Basically implementing a singleton pattern means writing a class with a private constructor and a static method to build itself. Also check PHP site for it: http://www.php.net/manual/en/language.oop5.php and http://it2.php.net/manual/en/book.spl.php
class A {
protected $check;
private function __construct($args) {
}
static public function getSingleton($args) {
static $instance=null;
if (is_null($instance)) {
$instance=new A();
}
return $instance;
}
public function whoami() {
printf("%s\n",spl_object_hash($this));
}
}
$c=A::getSingleton("testarg");
$d=A::getSingleton("testarg");
$c->whoami(); // same object hash
$d->whoami(); // same object hash
$b= new A("otherargs"); // run time error
<?php
class MyObject {
private static $singleInstance;
private function __construct() {
if(!isset(self::$singleInstance)) {
self::$singleInstance = new MyObject;
}
}
public static function getSingleInstance() {
return self::$singleInstance;
}
}
?>
class MyClass {
private static $instance;
public static function getInstance() {
if( !isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
}
Then call get instance using
MyClass::getInstance();
This is how I've set up my Singleton
<?php
class MySingleton
{
private static $instance;
private static $you;
private function __construct()
{
$this->you = "foo";
}
public static function singleton()
{
if (!isset(self::$instance)) {
$className = __CLASS__;
self::$instance = new $className;
}
return self::$instance;
}
public function getYou()
{
return $this->you;
}
public function setYou($val)
{
$this->you = $val;
}
}
?>
In file1.php, I do this:
require_once('session.php');
$session = MySingleton::singleton();
$session->setYou('bar');
echo $session->getYou(); //echoes 'bar'
In file1.php, I have a hyperlink to file2.php, where I have this code:
require_once('session.php');
$session = MySingleton::singleton();
echo ($session->getYou()); //prints 'foo' which gets set in the constructor
It seems it is creating a new instance for file2, which is why $you has the default value of foo. Where am I going wrong? Why don't I get the instance I was using in file1.php?
A singleton in PHP is only valid for the current request (as HTTP is stateless).
If you want to preserve the state of that object, save it in a session:
class MySingleton
{
private static $instance;
private static $you;
private function __construct()
{
$this->you = "foo";
}
public static function singleton()
{
session_start();
if (!($_SESSION['MyInstance'] instanceof MySingleton)) {
$className = __CLASS__;
$_SESSION['MyInstance'] = new $className;
}
return $_SESSION['MyInstance'];
}
public function getYou()
{
return $this->you;
}
public function setYou($val)
{
$this->you = $val;
}
}
Singletons are meant to be "single" during ONE request. For everything else you will have to serialize the object or use Sessions.
Static data only works within a single PHP program.
If your two scripts are running as separate pages they will not share any state.
Singletons in PHP are meant to return the same instance of the object during the same execution of the program, not between different pages o page loads. What you need is to store the object in the session (sending it to "sleep") and retrieving it later ("waking it up"), but beware, they are still different instances, one a clone of the other, and updating une will not update the other.
I am going to use singleton classes to manage both DB connections and references to application settings.
It seems a little messy to have to use the following code in every method in order to access the db class.
$db = DB::getInstance();
Is there a more efficient way of going about it?
Any advice appreciated.
Thanks
I often use the Registry pattern, where this behavior occurs as well. I always set a instance variable in the constructor of my models to point to the Registry entry;
class Registry {
private static $_instance;
private $_registry;
private function __construct() {
$_registry = array();
}
public static function getInstance() {
if (!Registry::$_instance) {
Registry::$_instance = new Registry();
}
return Registry::$_instance;
}
public function add($key, &$entry) {
$this->_registry[$key] = &$entry;
}
public function &get($key) {
return $this->_registry[$key];
}
public function has($key) {
return ($this->get($key) !== null);
}
}
Model example;
class MyModel {
private $_db;
public function __construct() {
$this->_db = Registry::getInstance()->get('dbKey');
}
/* Every function has now access to the DAL */
}
Instantiation example;
$dal = new Db(...);
Registry::getInstance()->add('dbKey', $dal);
...
$model = new MyModel();
$model->doDbStuff();
Another approach is to always pass the reference as a parameter to each constructor.
Of course I only use this behavior when most of the methods in my model use the reference, if only a few (one or two) methods have use of the reference, I call the Registry/Singleton like you showed.
It is not messy. This is an intended behavior of Singletons. And, actually, this is just one line of code. Do you wish to make it even more compact? :)
My preferred method is to create a Base class which all the classes that need db access descend from. Base calls the singleton(s) in its constructor. All its children call their parent constructor. e.g.:
class Base {
protected $db;
public function __construct(){
$this->db = DB::getInstance();
}
}
class Achild extends Base {
protected $var1;
public function __construct($arg){
parent::__construct();
$this->var1=$arg;
}
}
I know what you mean... hate that ::getInstance() stuff! So go and use static methods:
class DB {
private static $db;
public static function getInstance() {
if(!self::$db) {
self::$db = new DBconnector();
}
}
public static function query($query) {
return self::$db->query($query);
}
}
Usage is much nicer:
$result = DB::query('SELECT whatever;');
And if you use PHP 5.3 you can write a __callStatic similar to this, to forward all the method calls to the object:
public static function __callStatic($method, $args) {
call_user_func_array(array(self::$db, $method), $args);
}
And to make me happy, add an __autoloader so that you can access DB without any worries any time!
I have a class for interacting with a memcache server. I have different functions for inserting, deleting and retrieving data. Originally each function made a call to memcache_connect(), however that was unnecessary, e.g.:
mc->insert()
mc->get()
mc->delete()
would make three memcache connections. I worked around this by creating a construct for the class:
function __construct() {
$this->mem = memcache_connect( ... );
}
and then using $this->mem wherever the resource was needed, so each of the three functions use the same memcache_connect resource.
This is alright, however if I call the class inside other classes, e.g.:
class abc
{
function __construct() {
$this->mc = new cache_class;
}
}
class def
{
function __construct() {
$this->mc = new cache_class;
}
}
then it is still making two memcache_connect calls, when it only needs one.
I can do this with globals but I would prefer not to use them if I don't have to.
Example globals implementation:
$resource = memcache_connect( ... );
class cache_class
{
function insert() {
global $resource;
memcache_set( $resource , ... );
}
function get() {
global $resource;
return memcache_get( $resource , ... );
}
}
Then no matter how many times the class is called there will only be one call to memcache_connect.
Is there a way to do this or should I just use globals?
I would code another class using singleton pattern for getting the only instance of memcache. Like this -
class MemCache
{
private static $instance = false;
private function __construct() {}
public static function getInstance()
{
if(self::$instance === false)
{
self::$instance = memcache_connect();
}
return self::$instance;
}
}
and usage -
$mc = MemCache::getInstance();
memcache_get($mc, ...)
...
Pass in the MC instance:
class abc
{
function __construct($mc) {
$this->mc = $mc;
}
}
class def
{
function __construct($mc) {
$this->mc = $mc;
}
}
$mc = new cache_class;
$abc = new abc($mc);
etc.
I think you're looking for static properties here.
class mc {
private static $instance;
public static function getInstance() {
if (self::$instance== null) {
self::$instance= new self;
}
return self::$instance;
}
private function __construct() {
$this->mem = memcache_connect(...);
}
}
This implements a basic singleton pattern. Instead of constructing the object call mc::getInstance(). Have a look at singletons.
You should use dependency injection. The singleton pattern and static constructs are considered bad practice because they essentially are globals (and for good reason -- they cement you to using whatever class you instantiate as opposed to some other).
Here is something like what you should do in order to have easy maintenance.
class MemCache {
protected $memcache;
public function __construct(){
$this->memcache = memcache_connect();
}
}
class Client {
protected $MemCache;
public function __construct( MemCache $MemCache ){
$this->MemCache = $MemCache;
}
public function getMemCache(){
return $this->MemCache;
}
}
$MemCache = new MemCache();
$Client = new Client($MemCache);
$MemCache1 = $Client->getMemCache();
// $MemCache and $MemCache1 are the same object.
// memcache_connect() has not been called more than once.