See Objects of a class in php - php

How can i see How many objects of a class are loaded in php. Also do the objects get loaded in a single session on server? Or one can track objects from other sessions also while on the server side?
Actually i am confused. When an object is loaded with the PHP where does it reside? Is it in the browser? Is it in the session and expires as soon as the session expire?

Will this help?
<?php
class Hello {
public function __construct() {
}
}
$hello = new Hello;
$hi = new Hello;
$i = 0;
foreach (get_defined_vars() as $key => $value) {
if (is_object($value) && get_class($value) == 'Hello')
$i++;
}
echo 'There are ' . $i . ' instances of class Hello';

How can i see How many objects of a class are loaded in php.
I don't think there is a way to do this without you actually keeping count in the class's constructor.
When an object is loaded with the PHP where does it reside? Is it in the browser? Is it in the session and expires as soon as the session expire?
It resides inside the memory that the PHP process that gets called for that one request allocates. It expires as soon as the current request has finished or been terminated (or been unset()).
The session is something that helps identify a user across multiple requests. It survives longer - it expires when it gets destroyed, when the user's session cookie is deleted, or when the session reaches its expiry time.

An object is just a complex variable. It can hold a couple of simple types together and it can have functions.
Despite the numerous differences between simple types and objects, an objects is just a variable. Objects are not shared over sessions, or sent to browsers any more than simple integers or strings.

An object exists only on the server, in memory, and only for the lifetime of the script's execution unless saved into the user's $_SESSION. Even when saved, it ceases to be an object and instead becomes a serialized string. It can be reconstituted again into an object in the same session or a later session.
The script's lifetime refers to the moment the web server calls it until the moment the scripts final line has been processed. The PHP engine may dispose of objects no longer needed by the script through garbage collection, even before the script has fully terminated.

Related

PHP 8 Session Problem with Object serialization

I am facing a very strange Session problem on PHP 8(even though it doesn't work with 7.4 also, but on 7.3 it works great).
What i do is i cerated a class where i set up the Export Object and store it on Session $_SESSION['AjaxExport'][sessionid]. Now i want to load this object stored by reference on the ifram which processes the export. When i session_start it fails to load the session at all.
AjaxExporter Class
private function ExportIntro(){
while (ob_end_clean());
// remove any old ajax exports
unset($_SESSION['AjaxExport']);
$rnd = rand(1, 99999);
$this->sessionid = uniqid($rnd, true);
$_SESSION['AjaxExport'][$this->sessionid] = &$this;
Above, loads the modal where the user gets a link to start the Export. by clicking on that link i load the Below function which loads the Object from Session and start exporting by auto-reloading to export in process like (10%-20%...)
class NG_ADMIN_AJAXEXPORTER_CONTROLLER extends NG_ADMIN_BASE {
public function Export()
{
$sessionid = '';
if (!empty($_REQUEST['exportsess']) && isset($_SESSION['AjaxExport'][$_REQUEST['exportsess']])) {
$sessionid = $_REQUEST['exportsess'];
}
else {
return;
}
$exporter = &$_SESSION['AjaxExport'][$sessionid];
$exporter->sessionid = $sessionid;
$exporter->HandleToDo($_REQUEST['action']);
}
}
When the process tries to start, i get no session at all.
session_start(): Failed to decode session object. Session has been destroyed in...
Also tried to implement Seriazable on both classes but that not seam to work either because, even though the object is stored, there are no values in its properties so it's useless (even though i used reference &).
As i mentioned above, this code works just fine in php 7.3, the problems started since 7.4 and php 8
So, finally figured this out.
As a friend told me that if a class has static properties serialization may not work and i was loading Twig v3 on parent class, so i destroyed all the properties that may contained the "template" property from Twig and it worked.
Generally, cleaned my object to only contain the necessary sub-objects that needed to complete my exports.

Avoid session timeout reset when sending ajax request

Is it possible to tell codeigniter to skip session timeout reset if post request is coming via ajax to a particular controller function. I have a frequent ajax call inside user login dashboard to check something, but these calls keeps the session alive so even if the user stays inactive for 10 minutes (sess_expiration time) session wont be killed and they still remain logged in for ever.
If (and only IF) your Ajax call is completely session-agnostic (that is, it doesn't required to be logged in to run, it doesn't need any session data from the user, etc) you could serve the Ajax request from a separate ajax-specific controller and then inhibit the session library autoload when that specific controller is used.
If the ajax call requires a logged in user you're mostly out of luck.
However, if you meet these conditions, find the $autoload['libraries] section in application/config/autoload.php and use this dirty hack:
// Here, an array with the libraries you want/need to be loaded on every controller
$autoload['libraries'] = array('form_validation');
// Dirty hack to avoid loading the session library on controllers that don't use session data and don't require the user to have an active session
$CI =& get_instance();
// uncomment the one that fits you better
// Alternative 1: you only have a single controller that doesn't need the session library
// if ($CI->router->fetch_class() != 'dmz') array_push($autoload['libraries'], 'session');
// END alternative 1
// Alternative 2: you have more than one controller that doesn't need the session library
// if (array_search($CI->router->fetch_class(), array('dmz', 'moredmz')) === false) array_push($autoload['libraries'], 'session');
// END alternative 2
In the above code, dmz and moredmz are my two imaginary controller names that require the session library to not be loaded. Whenever these are NOT used, the session library is pushed into autoload and thus loaded. Otherwise, the session library is ignored.
I actually have this running on one of my sites in order to allow the health checks from my loadbalancer to run (once every 5 seconds on each application server, from both the primary loadbalancer and its backup) and fill up my sessions table with useless data and works like a charm.
Not sure what version of CI you're using, but the above code is tested on CI 3.1.11.
Now, as you state the Ajax call requires the session driver, the only way around this would be to mess a little with the Session driver itself. In 3.1.11, the session driver is located in system/libraries/Session/Session.php and the part you'd need to change is the final part of the constructor method (look from line 160 onwards). For this example, I'll assume your Ajax calls are handled by a specific controller called "Ajax"
// This is from line 160 onwards
elseif (isset($_COOKIE[$this->_config['cookie_name']]) && $_COOKIE[$this->_config['cookie_name']] === session_id())
{
$CI =& get_instance();
$new_validity = ($CI->router->fetch_class() !== 'ajax') ? time() + $this->_config['cookie_lifetime'] : $_SESSION['__ci_last_regenerate'] + $this->_config['cookie_lifetime'];
setcookie(
$this->_config['cookie_name'],
session_id(),
(empty($this->_config['cookie_lifetime']) ? 0 : $new_validity),
$this->_config['cookie_path'],
$this->_config['cookie_domain'],
$this->_config['cookie_secure'],
TRUE
);
}
$this->_ci_init_vars();
log_message('info', "Session: Class initialized using '".$this->_driver."' driver.");
In a nutshell, this example (haven't tested it so please do before deploying it, it may have a typo or two) will first instantiate the CI core and get the controller name from the Router. If it's a regular controller, it'll determine the new cookie validity as "now plus the cookie validity from the config". If it's the ajax controller, the cookie validity will be the same as the current validity (last regeneration time plus cookie validity.. had to reiterate it as the ternary operator requires it)
Afterwards, the setcookie is modified to use the pre-computed cookie validity depending on what the _config['cookie_lifetime'] value is.

after storing an object in session, it is automatically updated in session when object is changed. Why?

I found this interesting behavior in PHP. I can't understand why the object in session is getting updated even though I'm not explicitly storing it in session after it's been manipulated.
Can someone please enlighten me?
While the snippet below is written using Laravel 4 framework, the underlying session-related behavior is a function of PHP. Example code:
Route::get('/', function()
{
$stored = Session::get('testing');
if (!$stored)
{
$stored = new StdClass;
$stored->counter = 0;
Session::set('testing', $stored);
}
$stored->counter ++;
// Session::set('testing', $stored);
// if the above line were NOT commented out, i could understand why the counter keeps on increasing.
var_dump($stored->counter);
});
Since PHP objects are passed by reference (since PHP 5.0) and session write (if not executed directly with session_write_close() function) happens after script execution it is expected behavior from PHP itself.
So it goes as follows (I am not really speaking how exactly it goes in Laravel itself, but more in PHP's internals) :
You write object into SESSION
You change the object state
Scripts ends and write to a file happens with object changed state.
So if object is stored in session - always the latest object's state is written into session file.

Static variables across sessions

In ASP.NET if I declare a variable (or object) static (or if I make a singleton) I can have it persist across multiple sessions of multiple users (it it registered in a server scope) so that I don't have to initialize it at every request.
Is there such a feature in PHP? Thanks
You can set up APC and use the apc_store and apc_fetch functions.
http://us.php.net/manual/en/book.apc.php
You can do that with a PHP extension (written in C).
But if you want to write it in PHP, no. The best alternative is to write the variable to a file (file_put_contents()) at the end of each request, and open it at the start of each request (file_get_contents()).
That alternative isn't going to work for high volume sites because the processes will be doing read/write at the same time and the world will go all BLAAA-WOOO-EEE-WOHHH-BOOOM.
That doesn´t exist in PHP, however, you can serialize the data and put it either in a file on your hard drive or in /dev/shm/. You can also use memcache.
If you put your data in /dev/shm/ or use memcache the data will disappear on reboot.
Sadly, no. PHP's static keyword is limited to the current script instance only.
To persist data across script instances for the same session, you would use the session handling features.
To persist data across sessions, you would have to use something like memcache, however that requires additional set-up work on server side.
Symfony and other frameworks uses "PHPFastCache" who supports a wide range of drivers for caching data including APC, SQLite, MongoDB or simply your file system.
You can donwnload it at https://github.com/PHPSocialNetwork/phpfastcache
Here is an example with file caching :
use Phpfastcache\Helper\Psr16Adapter;
$defaultDriver = 'Files';
$Psr16Adapter = new Psr16Adapter($defaultDriver);
// Setter action
if(!$Psr16Adapter->has('test-key')) {
$data = 'lorem ipsum';
$Psr16Adapter->set('test-key', 'lorem ipsum', 300); // kept in cache for 300 seconds (5 minutes)
}
// Getter action
else {
$data = $Psr16Adapter->get('test-key');
}
You can use the Session Storage for this purpose, if you use the same sessionId for all sessions.
session_id('xyz');
session_start();
for ($i=0; $i < 100000; $i++) {
$_SESSION['counter'] = isset($_SESSION['counter']) ? $_SESSION['counter'] + 1 : 0;
}
echo "<br>session_id(): ".session_id() . "<br>counter: ".$_SESSION["counter"];
Try this script with 2 browsers and you will see that this method shares the data across both browsers - and is very, very fast.
you could store serialized copies of an object inside session
class test{
private static $instance;
public property;
private __construct(){}
public getInstace(){
if(!self::$instance){
self::$instance = new test;
}
return self::$instance;
}
}
$p = test->getInstance();
$p->property = "Howdy";
$_SESSION["p"] = $p;
next page
$p = $_SESSION["p"];
echo $p->property; // "Howdy"

Why can't I store a PHP class instance as a SESSION variable

I have a PHP script that is called in 2 ways from a Dojo Ajax xhrGet call.
The first time it is called with an "init" argument which causes the script to create an instance of the StateList class and read in a file of state names.
session_start();
#include('StateList.php');
require_once('phplog.php');
//start executing here
$comd=$_GET['nexturl'];
if($comd=="init") {
$st = new StateList("../data/statestxt.txt");
$_SESSION['statefile'] = $st;
}
The second and further times, another xhrGet call passes a "getstate" argument and the following code tries to get the instance ofr the StateList class from the SESSION array.
if($comd =="getstate") {
$st= $_SESSION['statefile'];
phplog("size=".$st->getSize());
}
However, the getSize() method is never executed, nor can I call any other method
on the reconstituted StateList class instance.
Note that this is one PHP script that DOES include the class definition at the top
and thus the class methods should be known and avaialble.
What am I missing here?
You need to include the class definition before you call session_start(), otherwise the object will not be deserialized correctly and will be an instance of __PHP_Incomplete_Class. Otherwise what you have should work fine.
You may need to serialize the $st object/variable before you store it. This will ensure that everything is saved to the session. This is definitely the way to go for object oriented code. When you want to use the data again, you must unserialize it.
This is one of those things that's hard to debug in isolation. Storing instantiated objects in PHP Sessions is always a little tricky, and not 100% guaranteed to work. Here's some general debugging tips that may help you figure this out.
First, check your apache error log. Are you getting a "method called on non-object error"? If so, this means you're not getting an object back out of the session. If not, is there an error that indicated your method call is failing for another reason?
Second, check to see what you're really getting out of your session.
if($comd =="getstate") {
$st= $_SESSION['statefile'];
//get the class of st
phplog("instance=".get_class($st));
//get a reflection dump of st
$ref = new ReflectionClass($st);
$string = $ref->__toString();
phplog("reflection=".$string);
}
Third, look at the serialized string value that is being stored in the session itself. Are you actually storing a serialized object? In your dev environment, set the session.save_path ini value in php.ini to something like /tmp, (or use the ini_set method to do the same thing):
session.save_path = "/tmp"
and then examine the files created in /tmp (or whatever folder). You should see a string that starts with:
statefile:O:..........
The name of the class that instantiated the object will also be included in there, as well as values saved to properties.
If you are going to store an object in the session it must be link text.There are a LOT of problems with serializing objects in PHP, let alone storing them in the session. I recommend against doing this altogether, and finding a different solution for your problem. If you are going to do it though, you should look into the 'magic methods' link text which you should define in your class to facilitate it's reinstantiation when it is called from the session.
Do you have session.auto_start enabled? The manual's session page states that if you do, you have to load the class definition differently:
If you turn on session.auto_start then the only way to put objects into your sessions is to load its class definition using auto_prepend_file in which you load the class definition else you will have to serialize your object and unserialize it afterwards.
http://php.net/manual/en/intro.session.php
As that page says, the serialization/unserialization of the object will normally be done automatically by PHP, but having session.auto_start enabled will change this.
Try this:
include('StateList.php');
require_once('phplog.php');
// start your session after including your class file
session_start();
//start executing here
$comd=$_GET['nexturl'];
if($comd=="init") {
$st = new StateList("../data/statestxt.txt");
$_SESSION['statefile'] = $st;
}
if($comd =="getstate") {
// the ampersand creates a reference, preserving any further changes to your session data
$st = &$_SESSION['statefile'];
phplog("size=".$st->getSize());
}

Categories