PHP Singleton: not holding instance - php

I'm just becoming dive into php after ages working in vb.net.
I wanna write a logger class that runs as singleon over my webapp, here the code:
class cLog{
private $data = NULL;
static private $instance = NULL;
static public function getInstance(){
if(self::$instance == NULL){
echo "empty!";
self::$instance = new cLog();
}
return self::$instance;
}
private function __construct(){
}
private function __clone(){
}
public function getData(){
return self::getInstance()->data;
}
public function trace($o){
self::getInstance()->data[] = $o;
}
}
What I expect is that, as i switch between pages of my application that make several calls to the cLog::trace() method, the data array increases and it's filled with all traces. But what I get is: everytime i run a page, the $instance is null so the object restarts (as you can see, I put an echo "empty!" line in the instance getter: it shows everytime)
I guess there's something I'm misunderstanding in the php application-lifecycle....
Here there's an usage example:
cLog::getInstance()->trace("hello world");
$logs = cLog::getInstance()->getData();
Thanks

PHP uses a "share nothing" architecture. This means (among other things) that nothing is shared between page loads. Unlike .NET, where the application is started on the first page hit and runs until stopped, just servicing requests as they come. In PHP, every time a page is requested the application is essentially compiled and run from scratch.

The PHP life cycle is from "page start to load" to "page ended load".
Generally speaking, every time you load a new page, everything starts from scratch.
You might be able to do some... interesting... things with session data to get your logger to work the way you want it to.
Good luck!

But what I get is: everytime i run a page, the $instance is null so the object restarts
...
I guess there's something I'm misunderstanding in the php application-lifecycle....
PHP's application-lifecycle mirrors that of HTTP. Each request for a page/URI is stateless. Each request knows nothing about the other requests. This is by design. The behavior you described is PHP acting as it should.
You need to take extra steps to have each request know about what happened in other requests. (PHP's session handling is one way to do this)

Instead of addressing your question on application life cycle in PHP, I would like to make a recommendation on using a prebuilt logging class.
The Zend Framework has Zend_Log which uses the Factory pattern and has a wide variety of Writer objects to log to databases, the filesystem, email, and so forth.
http://framework.zend.com/manual/en/zend.log.writers.html
You can use Zend_Log without needing any other part of the library, so it should be easy to adapt to your current system.

Related

Singletton Pattern not respected in PHP

I need a few variables to be shared accross several sessions. To do this, I thought I could use a class with a singleton pattern storing the variables, so each user (session) would just have to include the class and access its data.
I proceed with the following way :
<?php
require_once('team.php');
class Game {
private static $_instance = null;
private $team1;
private $team2;
public function getTeam($num) {
if ($num == 1) return $this->team1;
if ($num == 2) return $this->team2;
}
private function __construct() {
$this->team1 = new Team();
$this->team2 = new Team();
$this->team1->init_team(1);
$this->team2->init_team(2);
}
public static function getInstance() {
if(is_null(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
}
?>
Then I try to use the class like this :
$game = Game::getInstance();
$player = new Player();
...
$game->getTeam($team)->addPlayer($player);
Here is the problem : two players from a same team can't see each other when displaying all the members of their teams. Moreover, when I use the following instruction on 2 different sessions :
spl_object_hash(Game::getInstance());
The output is different, whereas I would expect it to be the same, assuming that it works like Java classes's hashcodes.
Any help regarding this issue would be appreciated. Thanks for reading.
When running a PHP application, every request starts a new instance of the application.
Your code IS running how you expect it to, but PHP doesn't run how you expect it to. It is not comparable to the way Java runs.
If you were to start a HTTP server to serve your PHP application and you had 10 concurrent visitors, you would see 10 new processes running on your server - each one containing a different instance of the application for each visitor.
However, if you were to create your HTTP server in Java and have 10 concurrent visitors, you would only see 1 process.
If you are looking to have persistent data in PHP which can be displayed to different users you should look into storage systems such as MySQL.
Every page run is distinct PHP application. This means that every user (on page call) is using his own compiled version of app, which will be deleted afterwards.
Singleton it not for that. It's just to ensure there is only one instance of object. But this object "lives" solely within separately compiled application.
You should use database for this kind of things (or any other kind of storage)

PHP persist data between pages without using $_GET and $_POST

Okay, so before I receive any abuse from this post, I'd like to state that I am all for following normal principals for persisting data, however today when I was developing I had an idea to create a class which sent a JSON object between pages simply using its own getter and setter methods.
class Persist {
private static $instance;
private static $object;
// singleton instanciation of the class
public static function getInstance() {
$object = __CLASS__;
!isset(self::$instance) ? self::$instance = new $object : false;
return self::$instance;
}
set__object($curr_object) {
self::$object = $curr_object;
}
get__object() {
return self::$object;
}
}
My question is, does this object get set exclusively to one user, or would it become system wide, I know that PHP is a server side language, so I assume the Object is created on the server.
Will each user have their own Persist object created or will there be one shared one, obviously one shared object would be a huge problem.
Thanks in advance,
Alex.
PHP is stateless. Each request will run usually in its own process/thread and the process/thread will stop after the script is done. Each instance of a class (also singletons) will thus be existing for the duration of that request. This is unlike c#/.net for example, where the entire web application is run like an application that handles multiple requests. So, no, it is not possible this way.
To share/persist data over multiple requests you will need to use something on disk or some external tool. Think of: sessions, databases, memcache, apc, etc.

Scope of Static Members in PHP and Concurrency

I have a class that is declared in my application that has a private static member like so:
class SomeClass{
private static myMember = array();
public static getterFunction(){}
public static setterFunction(){}
}
My question / concern is that multiple requests (i'm thinking like a thread in Java) would be able to modify this static member. My understanding of php scope and static members is that they are in the request scope and a new variable is created for each new request and subsequently destroyed after the request has been fulfilled. That said, this would be a difficult thing to test (at least i can't think of an easy way) so i'd rather be safe than sorry.
Is my assessment correct? The PHP docs i've read are pretty crappy in terms of detail so I haven't been able to authoritatively answer yet...
No data, none, is persistent or shared across different instances of PHP scripts unless you explicitly make it so (for example using sessions, databases, files, shared memory). Each PHP instance is its own thing, and each new request causes the webserver to start a separate instance.
So yes, you are correct.
You don't have shared memory by default in PHP. Every single request is being processed in separate process, so they do not know about each other.
I hope I understood your question correctly.
For example:
You have a simple script.php file that sets private field in a class when GET parameter passed:
<?
class A {
private $x = 1;
public function setX($x) {$this->x = $x;}
public function getX() {return $this->x;}
}
$a = new A();
if (!empty($_GET['x'])) {
$a->setX($_GET['x']);
sleep(3);
}
echo $a->getX();
?>
You do two requests at once:
GET /script.php?x=5
GET /script.php
Second request will print you "1". Yes, you are correct!

PHP vs ASP.NET static variables

Static variables in ASP.NET caught me off guard today. Then i became freaked out, because this means either i have a fundamental misunderstanding of static variables in the world of the web or ASP.NET does not act like i thought it would.
So in ASP.NET
public class MyClass {
public static bool myVar = true;
}
If ASPUserA sets MyClass.myVar = false every other user on the system would experience these changes. So, ASPUserB would have myVar = false. My Source: http://www.foliotek.com/devblog/avoid-static-variables-in-asp-net/
class MyClassPHP {
public static $myVar = false;
}
If PHPUserA sets MyClass::$myVar = true does this mean that every user on the system experiences these changes???
Thank you.
Upon further research i did this;
class MyClassPHP {
public static $myVar = 0;
}
Then i had users who went to a page do this
MyClassPHP::$myVar++;
echo MyClassPHP::$myVar;
It always was 1. No matter how many times i refreshed or simultaneous connections... WOHHH that was a great conclusion, or else i am screwed!!
ASP.NET update
Upon further research and testing things i found this.
public partial class MyPage : System.Web.UI.Page
{
public static int myInt = 0;
protected void Page_PreInit(object sender, EventArgs e)
myInt++;
}
}
Then my page can display myInt.
Between the browsers (Firefox and chrome) the myInt was progressively higher as i refreshed the page. So this does not matter if your class is static. It only matters if you have static variables. They are application wide.
When running in IIS:
A static variable is not "page" specific. It is "AppDomain" specific. The only relation to the "page" would be the path (so to speak) of the variable (MyProject.MyPage.MyVariable for example). Because all users of your application are running in the same AppDomain (i.e. same IIS application folder), then they will all use the same static variable. So... eventually your users are going to see each each other's information since they are all sharing that one single static variable.
PHP however tracks statics PER USER INSTANCE, so I guess you could call them "safer from the singleton dangerzone".
No, PHP isn't as stupid as ASP.NET (does it seriously do that?). Static variables in PHP are per instance (it's not like ASP.NET where the whole page is one instance, each user gets their own PHP instance).
If 2 users go to a PHP page, and on one page MyClass::$myVar = true is ran, it doesn't affect the other user.

Every client request is a new instance of the class?

I wrote a class that builds some url in a page every time there is a client request to the server. In a hypothetical scenario in which 100 clients, at the same time, require a server connection, it should produce 100 instances of that class, right?
So I would like to know what would be the result of many instances at the same time on the page and if this is a good practice to solve my problem with the "url generator".
Thanks
[EDIT]
What I tried to do it was to use __set() method and overloading to build the URLs. The fact is that I started to study object-oriented programming in php and I wanted to try a practical application of this method. Here is a piece of code:
Class BuildPath {
private $ServerPath;
private $ServerUrl;
private $UrlPath;
private $data;
function __construct()
{
$this->ServerPath = $_SERVER['DOCUMENT_ROOT'];
$this->ServerUrl = $_SERVER['HTTP_HOST'];
$this->UrlPath = $_SERVER['REQUEST_URI'];
$this->data = array();
}
public function __get($key) {
return $this->$key;
}
public function __set($key,$value)
{
$this->data[$key] = $value;
}
// others methods
After reading some of the comments I think you are misunderstanding what PHP is and isn't. Each time a user makes a request to the page it is "creating an instance" as you say. After the page is loaded the "instance" is removed. This is how PHP works.
Singleton classes will not share data with one users instance with another users instance but instead share that users intsance of that class with that same users instance of another class.
This is how PHP operates and is normal. Since php doesn't "store" data between each request this is where memcache or mysql come into use or sessions.
One thing to be aware of is that PHP has no application scope, meaning that there is no shared memory between requests. A database (mysql) or in memory store (memcache) is typically used to share the state of objects between requests.
Without knowing more specifics to your question, in general, each request made to the webserver will spawn a new instance of your class, but each class will only be aware of it's own state unless you have a mechanism to share it.

Categories