I have a singleton class that I am using as part of a CAPTCHA system to generate the code and image etc.
I have one script included on the html form that loads the class singleton, generates the code and image, and outputs it to the browser. I then have another script to validate and process the form. This loads the class singleton to retrieve the instance that was created previously, and calls the function to validate the code.
The problem I'm having is that when I'm validating the form the code that was generated on the form has changed or is completely absent when I come to validate it!
I haven't started or stored anything in the php session, but a session is created on the page the form is loaded in. Is the instance of the singleton somehow linked to that session? If it's a named session or something?
OR...have I completely misunderstood how singleton classes work? In which case can anyone tell me how I can retrieve the instance of the class that is created on the html form page to use again to validate the code in the form processing script? - And maybe tell me how I should be using singletons!
Many thanks.
Singletons exist for the duration of the request, not the duration of the session.
The idea of a singleton is to provide access to the same object across all included scripts, without having to use any explicit initialisation logic.
So, the first call to $foo = MyObject::singleton() creates a new MyObject, but the second call will simply return that object instead of creating a new one. This is incredibly useful for classes that access external resources such as databases and files.
OR...have I completely misunderstood how singleton classes work?
Partially. Since PHP has no ASP.NET alike application variables, objects in PHP live as long as the request does, unless serialized (for example in a session).
As a solution to your problem: save the captcha code (or the captcha class, which is a bit of overkill imho) in a session variable, like $_SESSION['captcha'].
No, it's not.
You'd have to serialize your singleton object and store it to the session when your code execution ends. When the next page is displayed, you can unserialize the object from your session.
PHP serializes/unserializes objects automatically when you assign them to a session.
This only works correctly under the precondition that your singleton does not use link identifiers to external resources.
Here is an example implementation taken from the comments in PHP docs
class SessionSingleton {
/**
* Returns an instance of the singleton class.
* #return object The singleton instance
*/
public static function _instance()
{
// Start a session if not already started
Session::start();
if ( false == isset( $_SESSION[ self::$_singleton_class ] ) )
{
$class = self::$_singleton_class;
$_SESSION[ self::$_singleton_class ] = new $class;
}
return $_SESSION[ self::$_singleton_class ];
}
/**
* Destroy the singleton object. Deleting the session variable in the
* destructor does not make sense since the destructor is called every
* time the script ends.
*/
public static function _destroy()
{
$_SESSION[ self::$_singleton_class ] = null;
}
/**
* Initialize the singleton object. Use instead of constructor.
*/
public function _initialize( $name )
{
// Something...
}
/**
* Prevent cloning of singleton.
*/
private function __clone()
{
trigger_error( "Cloning a singleton object is not allowed.", E_USER_ERROR );
}
private static $_singleton_class = __CLASS__;
}
Related
I just stumbled over a PHP class and wonder if there was a valid reason for the way one of it's methods is written.
LogUtility::getLogger() is called as a static method in various other PHP classes of the PHP application. Does the used if statement make sense or is $logManager always null when getLogger() is called?
class LogUtility
{
/**
* #var LogManager
*/
protected static $logManager;
/**
* #return Logger
*/
public static function getLogger($name)
{
if (!self::$logManager) {
self::$logManager = GeneralUtility::makeInstance(LogManager::class);
}
return self::$logManager->getLogger($name);
}
}
You could quickly whip up a test, like below, and test / prove it yourself:
class someClass {
protected static $stored;
public static function test() {
echo '<br>Stored state:' . self::$stored;
if ( ! self::$stored) {
self::$stored = "set";
}
}
}
someClass::test();
someClass::test();
Output is:
Stored state:
Stored state:set
So, based on this simple test, the answer is Yes, the if statement makes sense. The static variable is set and maintained.
$logManager is set to a property of the class, so for now, its pretty much an empty class, just returning with a getter, the instance. This just sets the code to just reuse the object. So a bit of recycling code there.
In the class you are now able to play with this object freely. So if you run this LogUtility from another piece of code by setting it to a var, you have already instantiated it. e.g. $util = new LogUtility();now if someone comes along and tries to instantiate it again, $anotherUtil=new LogUtility(); this recycles the class, passing back the already instantiated instance, instead of instantiating a new one.
Therefore, yes, it kept it. Although, the var doesn't contain the "same value" per say, it contains a reference to the "same" class that was instantiated with he other variable, so it ends up a copy of the same instance there.
It will be null for only the first call in a lifecycle. This implements a design pattern called Singleton.
Check out https://sourcemaking.com/design_patterns/singleton/php/1
I'm running into a problem when passing an object across different classes and trying to have only one instance of it instead of multiple clones.
TLDR version:
If I have objects A->B->C, where C gets passed A by way of B as a parameter on creation, will C->A->B access the original B that had created it, or a copy of that B? How many copies of B are there in the system memory now?
Slightly more detailed version:
Let's say I have a (perhaps overly convoluted) nested class structure for handling a server-based request. The first step is to instantiate an object of class Session, and then within it, create an object $handler of class Handler. However, as $handler will need to have access to the internal attributes of $session (and multiple other objects created within it, like $user or $database, whose purposes ought to be self-explanatory), I then pass it on as a parameter:
class Session {
public $handler;
public function __construct() {
$this->handler = new Handler( $this );
//DO STUFF HERE
}
}
The Handler class inherits the session like this:
class Handler {
private $session;
public function __construct( Session $inherited_session ) {
$this->session = $inherited_session;
}
}
Side note: $session is set to private to avoid even the slightest chance of infinite loops down the line, of the $this->session->handler->session->handler variety.
Now, according to my understanding and all the research I've done, PHP passes objects by reference, so the $this->session object within this Handler ought to be accessing the same object in the system memory as the original session? Not a copy of itself?
Yet here's my problem. Suppose now I create a third-level nested object within the Handler class, of class Dashboard, and want to pass the original $session to it (not, mind it, just the Handler object itself). Off we go, so we put this somewhere within the Handler class:
$dashboard = new Dashboard( $this->session );
The Dashboard constructor inherits the session in exactly the same way as Handler did:
class Dashboard {
private $session;
public function __construct( Session $inherited_session ) {
$this->session = $inherited_session;
}
}
However, it doesn't seem able to access the instance of Handler that had called it, and by now it appears that we have multiple copies of $session and $handler floating about - and I'd very much like to understand why, because it contradicts everything I understand about references.
Here's an example of this pathological behaviour - say we have a variable in Handler:
public $temp_var;
that the constructor of Handler assigns a value:
$this->temp_var = '123';
and then we try accessing it from within the Dashboard class as $this->session->handler->temp_var. That returns NULL. Why? Did $dashboard inherit a copy of $session on initialisation that doesn't have an initialised ->handler to call on? How can I make it so there is only one (unique) object of each class, and updating the internal (public) variables of $handler would get correctly passed on to $dashboard->session->handler? Or am I just making some obvious / idiotic mistake somewhere and completely not seeing it?
Note #1: any variable set in $session as $this->var is correctly accessible from $dashboard->session->var, so double-level nesting works as expected; it's triple-level one that doesn't.
Note #2: I've already thought of simply passing $handler as a parameter to all of its nested objects along with $session (and if no solution exists, this is what I'll have to do), but it doesn't solve the original problem of $this->session->handler being somehow and inexplicably different from the original $handler within its nested objects.
Oh, and my thanks to anyone who managed to read through all this!
As far as I understand, you're dealing with composition not with inheritance here.
So, you have a Session which is passed to a Handler, the Handler and Dashboard both "know" the session through composition (keeping a reference on the private variable).
I don't understand why do you need this sort of circular reference, but if you want to access the Handler from Dashboard, why not passing the Handler to it?
Besides that, it looks like you are storing the handler in a local scoped variable (I've been away from PHP the last two years, but...)
class Session {
public function __construct() {
// isnt $this->handler = new Handler( $this ) ??
$handler = new Handler( $this );
}
}
From a conceptual point of view, there's not "nesting", only references, so I dont think that the "three levels" does anything to do with that.
Hope it helps!
Here's an example I've modified the Session and privacy just to verify that the $session is still the same
I'm getting started with objects in PHP and I was wondering when they get deleted. Is it when the PHP file gets finished loading or when it's finished with the function I'm calling? is there anyway to keep the object alive so it can be called in another instance when the file is loaded.
There's a distinction to be made between objects dying and objects being out of scope.
If you are concerned with the logistics of memory management and garbage collection in PHP then as T.J. Crowder pointed out you could read the manual on garbage collection in PHP.
If on the other hand you are more concerned with variable scope, then the answer is that the scope of variables is typically bounded to the block they are declared in. But you can also create global variables, and access them using the global keyword inside of functions - although global variables are generally a bad idea. See the manual for details.
And as far as persisting variables beyond a script, this can only be accomplished via some sort of storage mechanism. In the context of web applications, that is usually accomplished using session state but be careful that the nuances of persisting objects from one session to the next (i.e. one invocation of a script to the next) may be different depending on whether the session state is stored in-process, or out of process. In case it's the latter then the objects will be serialized and deserialzed which makes things a little more complicated.
PHP memory vars is garbage collected, usually they are being removed (decrease ref) when request ends, function out of scope .. etc.
you still can go with singleton pattern, and load only not loaded objects
note that this only works for each single request, if you want to keep the object in memory for more than one request, that's wont work for php,
/**
* Singleton class
*
*/
final class UserFactory
{
/**
* Call this method to get singleton
*
* #return UserFactory
*/
public static function Instance()
{
static $inst = null;
if ($inst === null) {
$inst = new UserFactory();
}
return $inst;
}
/**
* Private ctor so nobody else can instance it
*
*/
private function __construct()
{
}
}
To use:
$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();
$fact == $fact2;
code example taken from https://stackoverflow.com/a/203359/1291995
I have the following Singleton Class in PHP.
class CounterBalance{
private static $instance;
private $counterBalance;
private function __construct(){
$this->counterBalance = mt_rand(1, 4);
}
// Getter method for creating/returning the single instance of this class
public final static function getInstance() {
if(!self::$instance) {
self::$instance = new CounterBalance();
echo "CounterBalance constructed <br/>";
}
return self::$instance;
}
public function getCounterBalanceValue() {
return $this->counterBalance;
}
}
But in the class when I do something like
CounterBalance::getInstance()->getCounterBalanceValue();
on the same php page, it works properly. But it not working properly across pages. I get more than one instance of CounterBalance, when I do the same function call in the subsequent php page.
Can anyone one please explain why this happens.
Thanks in advance.
Welcome to the stateless world of HTTP.
A singleton can only persist for the single page load (or any other PHP data structure, for that matter). When the php process dies, the singleton dies with it. The next time a page is loaded the singleton is created all over again. The singleton is only alive in the context of that single process. If you tried to create ten instances of it during a single script execution you would maintain the single instance.
If you need data persistence across pages you'll have to implement an agent of state. For example, the $_SESSION or $_GET superglobals or store data in a database (for example) and re-retrieve it on subsequent page loads.
I'm currently creating blog system, which I hope to turn into a full CMS in the future.
There are two classes/objects that would be useful to have global access to (the mysqli database connection and a custom class which checks whether a user is logged in).
I am looking for a way to do this without using global objects, and if possible, not passing the objects to each function every time they are called.
You could make the objects Static, then you have access to them anywhere. Example:
myClass::myFunction();
That will work anywhere in the script. You might want to read up on static classes however, and possibly using a Singleton class to create a regular class inside of a static object that can be used anywhere.
Expanded
I think what you are trying to do is very similar to what I do with my DB class.
class myClass
{
static $class = false;
static function get_connection()
{
if(self::$class == false)
{
self::$class = new myClass;
}
return self::$class;
}
// Then create regular class functions.
}
What happens is after you get the connection, using $object = myClass::get_connection(), you will be able to do anything function regularly.
$object = myClass::get_connection();
$object->runClass();
Expanded
Once you do that static declarations, you just have to call get_connection and assign the return value to a variable. Then the rest of the functions can have the same behavior as a class you called with $class = new myClass (because that is what we did). All you are doing is storing the class variable inside a static class.
class myClass
{
static $class = false;
static function get_connection()
{
if(self::$class == false)
{
self::$class = new myClass;
}
return self::$class;
}
// Then create regular class functions.
public function is_logged_in()
{
// This will work
$this->test = "Hi";
echo $this->test;
}
}
$object = myClass::get_connection();
$object->is_logged_in();
You could pass the currently global objects into the constructor.
<?php
class Foo {
protected $m_db;
function __construct($a_db) {
$this->m_db = $a_db;
}
}
?>
I recently revamped my framework in preparation for the second version of our company's CMS. I undid a huge amount of the things I made static in order to replace them with normal objects. In so doing, I created a huge amount of flexibility that used to rely on me going through and hacking into core files. I now only use static constructs when the only alternative is global functions, which is only related to low-level core functionality.
I'm going to show a few lines of my bootstrap.php file (all of my requests get sent through that file, but you can achieve the same result by including it at the top of every file) to show you what I mean. This is an pretty hefty version of what you'd probably use in your situation, but hopefully the idea is helpful. (This is all slightly modified.)
//bootstrap.php
...
// CONSTRUCT APPLICATION
{
$Database = new Databases\Mysql(
Constant::get('DATABASE_HOST'),
Constant::get('DATABASE_USER'),
Constant::get('DATABASE_PASSWORD'),
Constant::get('DATABASE_SCHEMA')
);
$Registry = new Collections\Registry;
$Loader = new Loaders\Base;
$Debugger = new Debuggers\Dummy; // Debuggers\Console to log debugging info to JavaScript console
$Application = new Applications\Base($Database, $Registry, $Loader, $Debugger);
}
...
As you can see, I have all kind of options for creating my application object, which I can provided as an argument in the constructor to other objects to give them access to these "global" necessities.
The database object is self-explanatory. The registry object acts as a container for object I may want to access elsewhere in the application. The loader acts as a utility for loading other resources like template files. And the debugger is there to handle debug output.
I can, for example, change the database class that I instantiate and, voila I have a connection to a SQLite database. I can change the class of the debugger (as noted) and now all of my debug info will be logged to my JavaScript console.
Okay, now back to the issue. How do you give other objects access to all of this? You simply pass it in an argument to the constructor.
// still bootstrap.php
...
// DISPATCH APPLICATION
{
$Router = new Routers\Http($Application);
$Router->routeUri($_SERVER['REQUEST_URI']);
}
...
Not only that, but my Router (or whatever object I construct with it) is more flexible, too. Now I can just instantiate my application object differently, and my Router will behave differently accordingly.
Well, if you already have some object by which you refer to the blog system, you can compose these objects into that, so that they're $blog->db() and $blog->auth() or whatever.