I've noticed that the keyword static in PHP is not that static at all.
Lets say Elmo is my singleton:
class Elmo
{
private static $instance;
private function __construct()
{
echo 'Elmo says constructor\n';
}
public static function getInstance()
{
if (!isset(self::$instance))
self::$instance = new Elmo();
return self::$instance;
}
public function boo()
{
echo 'Elmo says boo!\n';
}
}
And the following file is just a regular .php script.
<?php
Elmo::getInstance()->boo();
Elmo::getInstance()->boo();
// Output:
// Elmo says constructor
// Elmo says boo!
// Elmo says boo!
?>
Every new page Elmo gets re-constructed. Why don't subsequent pages have the following output?
<?php
// Output:
// Elmo says boo!
// Elmo says boo!
?>
I hope someone can enlighten me on this, thanks!
because on every page load all memory is wiped ?
Static scoping does not mean it will stay in memory forever, it means that the variable operates outside the program call stack, and will persist during the execution of the script. It is still cleared after the program ends.
This is because every time you do a page load it runs {main} separately. This would be like running a java program two separate times and the static property not being retained. Elmo::$instance will only remain instantiated in the context of the same script. If you want it to work across page loads, you can serialize it in the session (or DB) and check this instead of $instance each time:
const SESSION = 'session';
public static function inst() {
!isset($_SESSION[self::SESSION]) and self::init();
self::$inst = $_SESSION[self::SESSION];
return self::$inst;
}
private static function init() {
$_SESSION[self::SESSION] = new self;
}
Related
I have a page (index) that acts as an entry point to my application.That page will call function sayHi() and display something based on value (normally the function will do a DB query and display information). I want to know the best method to use.
First method : a new object will always be created each time a user does a request (or page refresh).So is it problematic for page performance (or memory) ?
Second method : let's say we have 2 users that query an index page at exactly same time (with different value), what will happen (race condition) ?
Index page
<?php
require_once('firstTest.php');
$value = $_GET['params'];
// 1st method
$first = new FirstTest();
$first->sayHi($value);
// 2nd method
$second = FirstTest::getInstance();
$second->sayHi($value);
firstTest class:
class FirstTest extends Singleton
{
public function sayHi($value)
{
echo 'value is : ' .$value;
}
}
firstTest (2nd method)
class FirstTest
{
public function sayHi($value)
{
echo 'value is : ' . $value;
}
}
singleton class
abstract class Singleton
{
protected static $instance;
protected final function __construct(){}
protected final function __clone(){}
public final function __sleep(){
throw new Exception('cannot serialize');
}
public static function getInstance(){
if (self::$instance === NULL)
self::$instance = new self();
return self::$instance;
}
}
In PHP every request is (at least logically) a different process and your variables are all created and destroyed within that request.
If you need to instantiate FirstTest many times within the same request, of course you will get better performance and less memory usage by using a singleton than by instantiating that many new objects. But as far as I understand you just instantiate it once anyway, so it makes no difference.
I am rather new to using PHP OOP and attempting the following:
$this->array = new array();
$this->array[1] = new myClass($UniqueName);
Within myClass I have a loop sending a message to the console every 5 seconds displaying the unique name. While the application is running new instances of the myClass will be created ( 1, 2, 3, 4, etc..), older ones become irrelevant and should be removed.
When I unset an array object the loop from that class keeps sending messages to the console.
unset($this->array[1])
My concern is that the class is not really gone wasting resources. As for the loop I could manually cancel it before running unset but it seems like its hiding my problem from view.
Hopefully this makes sense and someone can help me understand if this is possible.
Solution to my own problem. Here is a stripped down version I am testing with. The Issue is with the timer within myClass. It seems that because the timer is still running the class will not destruct. This has just been wishful thinking on my part that it would also terminate. Removing the timer allows the destruct to occur.
class myClass extends DefaultConfig {
public $fileName;
public $logLevel;
public $loop;
public $config;
public $db;
function __construct ($loop, $db, $config) {
$this->fileName = 'myClassObject';
$this->logLevel = 3;
$this->loop = $loop;
$this->config = new Config($config);
$this->HB();
}
function __destruct() {
print "Destroying " . $this->fileName . "\n";
}
public function HB(){
$this->loop->addPeriodicTimer(1, function($timer){
$this->Logging(3, $this->fileName, $this->logLevel, "Server Message");
});
}
}
I am looking for a better understanding of how static methods work in php. I have been reading the article on the php manual site about static keyword in releation to methods, and class objects and I am curious about something.
Lets say I have this class:
class Something{
protected static $_something = null;
public function __construct($options = null){
if(self::$_something === null && $options != null){
self::$_something = $options
}
}
public function get_something(){ return self::$_something }
}
So you instantiate this on index.php, so you do something like:
$class_instantiation = new Something(array('test' => 'example'));
Great, at this point $_something contains an array of key=>value, on this same page we can do:
var_dump($class_instantiation->get_something()); // var dumps the array we passed in.
BUT
If we now create sample.php and do:
$class_instantiation = new Something();
var_dump($class_instantiation->get_something());
We get null back (I assume you went to index.php, instantiated the class and passed in the array, saw the var_dump THEN navigated to sample.php. It is understandable how this would return null if you only went to sample.php without first going to index.php.)
I assumed that static methods are "saved across all instances of the class", thus I should be able to instantiate the class with or with out an object passed into the constructor, assume that something is there and get back my array we created on index.php
So my question is:
How does static methods really work in terms of classes? Is there a way to do what I am trying to do with out the use of third party tools if I am just passing objects around?
The static property is static across the same PHP execution. If you run it on index.php, then at the end of execution it is destroyed. On sample.php it will be a new execution. This works as you expect (same execution):
//index.php
class Something{
protected static $_something = null;
public function __construct($options = null){
if(self::$_something === null && $options != null){
self::$_something = $options ;
}
}
public function get_something(){ return self::$_something; }
}
$class_instantiation = new Something(array('test' => 'example'));
var_dump($class_instantiation->get_something());
$class_instantiation2 = new Something();
var_dump($class_instantiation2->get_something());
Both objects dump:
array(1) {
["test"]=>
string(7) "example"
}
static in PHP also means that you could access to property/method without instatiating the class. It's hard to keep static variables across the same PHP execution as, often, your execution will end with a server response but as AbraCadaver says, they act as you expect within the same execution (same request, read that way)
In my PHP project I created a singletone class that mange my access tokens.
The tokens are some constant strings with timestamp of +/- 5 min hashed with SHA1.
I want that each page can access to this singletone instance (the same instance) because it holds the tokens. Also there going to be a procedure that refresh the tokens in that instance.
The name TokenManager with located in different php file.
I create the instance $TOKENS in different file.
<?php
require_once 'TokenManager.php';
$TOKENS = TokenManager::Instance();
And another file for refresh action (refreshTokens.php):
<?php
require_once 'Tokens.php';
global $TOKENS;
$TOKENS->refreshTokens();
var_dump($TOKENS->tokens);
In another page that is a web service (AddUser) I use the this Tokens.php instance as global.
require_once 'TokenManager.php';
require_once 'Tokens.php';
...................................
function start(){
global $userParams;
global $TOKENS;
//Check for all mandatory params
if(!ValidateParams()){
finish();
}
if(!$TOKENS->checkTokenAndGetChannel($userParams[PARAM_TOKEN])){
setError(ERR6_BAD_TOKEN, CODE6_DESC);
finish();
}
if(!isEmailValidByDrupal($userParams[PARAM_EMAIL])){
setError(ERR3_BAD_EMAIL, CODE3_DESC . $userParams[PARAM_EMAIL]);
finish();
}
finish();
}
The problem that each time I call refreshTokens.php and take the token I have each time new instance with a different values what makes the tokens each time invalid.
What can I do about that?
Well when a called PHP Script ends all objects are destroyed and a singleton class will not really help you here.
A singleton class can be used as a cache or storage during the entire runtime of one page-call.
In other words, the singleton instance alone cannot keep the data between script calls.
Save them in the session, in a file or a database.
#Edit: After discussing the issue we came up it is the best to use class constants, I present you an example here:
#Edit2: Rethought the discussion and a Singleton class is fine if you do it correct, I leave you an example here:
final class Tokens {
static private $instance = null;
private $tokens = array();
static public function getInstance() {
if(self::$instance === null) {
self::$instance = new self();
self::$instance->initialize();
}
return self::$instance;
}
private function initialize() {
$this->tokens[] = "erhdfhegrtoken1!";
$this->tokens[] = "4h43gherhtoken2!";
$this->tokens[] = "egegtoken3!";
}
public function getToken($index) {
$retVal = "";
if(isset($this->tokens[$index])) {
$retVal = $this->tokens[$index];
}
return $retVal;
}
private function __construct() { }
private function __clone() { }
}
Usage:
$tokens = Tokens::getInstance();
$myToken = $tokens->getToken(2);
I'm trying to learn about OOP, and create a singleton to return a settings object within a PHP script. For some reason, the instance never seems to get set.
I'm echoing a message getting settings anytime the singleton goes through its construct (it's silent if it just returns the existing instance).
When this is called from within a script, I'm getting dozens of these getting settings messages, one for each time I call mySettings::getSettings()-- $instance doesn't seem to be created, even when I try to dump it immediately after it is created.
Can anyone point out where I'm going wrong?
Here's the code:
class mySettings {
private $settings;
private static $instance;
private function __construct(){
$configfile = "myconfig.ini";
if(!$this->settings = parse_ini_file( $configfile )){
die('CONFIG NOT FOUND/PARSED');
}
}
public static function getSettings(){
if ( !self::$instance ){
echo "getting settings-- no instance found!";
self::$instance = new mySettings();
var_dump(self::$instance); // <-- dumps nothing
}
return self::$instance;
}
public function setParam( $key, $value ){
$this->settings[$key] = $value;
}
public function getParam( $key ){
return $this->settings[$key];
}
}
Your approach to creating a singleton looks correct.
Try with an empty constructor, there might be an issue with that die() statement there.
Does: // <-- dumps nothing mean you see a "NULL" being rendered or nothing at all?
Maybe you've got some output buffering that hides the var_dump() output.