I have a PHP script that runs in the background for a while (usually a few minutes, but this could be up to an hour or so). It contains a loop in which I need to create an object. I'm currently using the same name every time like this:
while (!$job_finished) {
$x = new MyClass();
$x->doStuff();
$x->doMoreStuff();
unset ($x);
// more code here
}
Since I'm creating $x repeatedly with the same name, will garbage collection properly clean up memory? Or should I use an array over $x such as
$x[$i] = new MyClass();
Actually I don't need to use the array. The unset() command will destroy the object and therefore I shouldn't worry. This is in the PHP documentation where it states:
The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence.
I tested it with the following code and it shows the destruct method being called before the end of the script indeed.
<?php
class A {
function __destruct() {
echo "cYa later!!\n";
}
}
$a = new A();
unset($a);
echo "hello";
sleep(10);
Yes, if you are keeping object references to an array, it will not release memory & will fail in last.
However, your code example shown will not issue memory problems as you are not keeping object's reference & overriding it always in loop.
Related
I know that once a script ends, all objects are destroyed and memory is returned. Does this also happen to function-scoped objects once the function ends that aren't accessible anyway?
For instance, I'm worried about memory leaks in my PHPUnit tests, wherein I create a new object for almost every test. Will this eventually overflow my heap if I run enough tests?
public function testMyFunction()
{
// Arrange
$myObject = new MyClass();
// Act
$return = $myObject->myFunction();
// Assert
$this->assertEquals(true, $return);
}
Should I be manually unsetting them for long-running scripts in an "Absterge" section?
public function testMyFunction()
{
// Arrange
$myObject = new MyClass();
// Act
$return = $myObject->myFunction();
// Assert
$this->assertEquals(true, $return);
// Absterge
unset($myObject);
}
PHP will garbage collect once all references to an object are gone.
unset is not needed. However, it is possible that you have a circular dependency, in which case it might not get garbage collected.
The only reason for using unset() is if you'd like to free memory before the end of the function. If there's still something else holding a reference to the thing that you're unsetting, unset() only removes the local variable, but not the object itself.
There's a special garbage collection cycle that cleans up as well circular references. You can control this with this php.ini setting:
http://ca2.php.net/manual/en/info.configuration.php#ini.zend.enable-gc
If you are interested in testing when and if your objects get garbage collected, you could add a __destruct method.
I have a code like this:
class Server {
private $stopper;
public function setStopper() { $this->stopper = TRUE; }
public function startServer() {
$consumer = new Consumer();
$consumer->onConsume(function($data) {
global $consumer;
// some processing
if( ?? ) { // how to access stopper here??
$consumer->stop();
// also how to access stopServer() here??
}
});
$consumer->consume();
}
public function stopServer() { ... }
}
This code is in a file that should run forever unless the setStopper() is called. So far I have set_time_limit to stop the code after a while. But I need to implement setStopper way so I can stop the server whenever needed, not "after a while".
I need this because, the onConsume is connected to a streaming API and runs the anonymous call back whenever new data is available and I don't want kill the php app on timeout due to some lock issues. I want to gracefully stop the server.
Can anyone please tell how to access the stopper or stopServer inside the callback? Can I use following syntax?
...(function($data) use ($this) {...
I also thought of storing the class value inside callback, but the setStopper is called dynamically and the value might not be updated!
Is there a better way to handle this situation?
Follow Up: php - Dynamically update Singleton class' value
You can create a Closure around the $consumer object as well as the lexical object $this (if you're using PHP < 5.4, you need to rename $this to something else, because you cannot use($this)):
$self = $this;
// You may not need to do this, I cannot remember off-hand whether
// closures have access to private variables or not
$stopper = $this->stopper;
$consumer->onConsume(function($data) use($consumer, $self, $stopper) {
if( $stopper ) {
$consumer->stop();
$self->stopServer();
}
});
See Example #3 on the linked to manual page.
I should also note here for completeness that if this is a long-lived process, then the objects being referenced inside the closure will hang around long after the function exits. For instance:
function makeAdder($x) {
return function($n) use($x) {
return $x + $n;
};
}
$adder = makeAdder(5);
echo $adder(2); // Output 7
echo $adder(5); // Output 10
echo $adder(4); // Output 9
This is a classic example of a closure. Normally, once the makeAdder function returns its inner variable $x will fall out of scope and be ready for garbage collection. Since it is however bound inside the anonymous function's scope, it will hang around indefinitely (until the script's termination) or the reference to the containing scope is also released (i.e. via unset($adder)). This means that once your function is called, extra references to $consumer, $this and $stopper will hang around until the class instance itself is destroyed.
Not being aware of this can lead to some serious performance issues.
the same problem here i use output buffers from ob_start/ob_end_flush
and one function i have should be dynamic (however parameters i push into should insert them in an array for later use for parsing buffers using $buffer)
in the parser associated to ob_start at a time i have these lines of code from one array full of data :
if(!empty($this->__b2))
array_filter ($this->__b2,function($var)use(**&$buffer**){
$buffer = preg_replace("/<\/body>/i", $var.'</body>', $buffer);
});
I use a only one class singleton ,and i use "::" a lot.
How you see in my case
array_filter was out of order without &$buffer
I have a CLI script written in PHP. In this script I have one instance of mainClass which contains a lot of instances of objects of other types which are stored in PHP arrays. How do I destroy $mainObject and all of the objects it contains?
EXAMPLE CODE:
class mainClass
{
private $_array1 = array();
private $_array2 = array();
private $_array3 = array();
public function __construct($data)
{
foreach ($data['a1'] as $val) {
$this->_array1[] = new Object1($val);
}
foreach ($data['a2'] as $val) {
$this->_array2[] = new Object2($val);
}
foreach ($data['a3'] as $val) {
$this->_array3[] = new Object3($val);
}
}
}
$mainObject = new mainClass($data);
function someFunction(mainClass $mainObject)
{
unset($mainObject);
}
Does unset($mainObject) will destroy it and all objects it contains?
Do I have to destroy every object separately?
Should I use destructor of the mainClass to destroy objects (call theirs destructors) that $mainObject contains?
You're looking for unset().
But take into account that you can't explicitly destroy an object.
It will stay there, however if you unset the object and your script pushes PHP to the memory limits the objects not needed will be garbage collected. I would go with unset() (as opposed to setting it to null) as it seams to have better performance (not tested but documented on one of the comments from the PHP official manual).
That said do keep in mind that PHP always destroys the objects as soon as the page is served. So this should only be needed on really long loops and/or heavy intensive pages.
kindly refer this link
Best way to destroy PHP object?
Best practice is to initialize that object to null.
$mainObject = NULL;
Reference:
What's better at freeing memory with PHP: unset() or $var = null
unset($mainObject); Will destroy object and memory will be free.
What is the exact order of object deconstruction?
From testing, I have an idea: FIFO for the current scope.
class test1
{
public function __destruct()
{
echo "test1\n";
}
}
class test2
{
public function __destruct()
{
echo "test2\n";
}
}
$a = new test1();
$b = new test2();
Which produces the same results time and time again:
test1
test2
The PHP manual is vague (emphasis mine to highlight uncertainty): "The destructor method will be called as soon as there are no other references to a particular object or in any order during the shutdown sequence."
What is the exact order of deconstruction? Can anyone describe in details the implementation of destruction order that PHP uses? And, if this order is not consistent between all the PHP versions, can anyone pinpoint which PHP versions change in this order?
First of all, a bit on general object destruction order is covered here: https://stackoverflow.com/a/8565887/385378
In this answer I will only concern myself with what happens when objects are still alive during the request shutdown, i.e. if they were not previously destroyed through the refcounting mechanism or the circular garbage collector.
The PHP request shutdown is handled in the php_request_shutdown function. The first step during the shutdown is calling the registered shutdown functions and subsequently freeing them. This can obviously also result in objects being destructed if one of the shutdown functions was holding the last reference to some object (or if the shutdown function itself was an object, e.g. a closure).
After the shutdown functions have run the next step is the one interesting to you: PHP will run zend_call_destructors, which then invokes shutdown_destructors. This function will (try to) call all destructors in three steps:
First PHP will try to destroy the objects in the global symbol table. The way in which this happens is rather interesting, so I reproduced the code below:
int symbols;
do {
symbols = zend_hash_num_elements(&EG(symbol_table));
zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t) zval_call_destructor TSRMLS_CC);
} while (symbols != zend_hash_num_elements(&EG(symbol_table)));
The zend_hash_reverse_apply function will walk the symbol table backwards, i.e. start with the variable that was created last and going towards the variable that was created first. While walking it will destroy all objects with refcount 1. This iteration is performed until no further objects are destroyed with it.
So what this basically does is a) remove all unused objects in the global symbol table b) if there are new unused objects, remove them too c) and so on. This way of destruction is used so objects can depend on other objects in the destructor. This usually works fine, unless the objects in the global scope have complicated (e.g. circular) interrelations.
The destruction of the global symbol table differs significantly from the destruction of all other symbol tables. Normally symbol tables are destructed by walking them forward and just dropping the refcount on all objects. For the global symbol table on the other hand PHP uses a smarter algorithm that tries to respect object dependencies.
The second step is calling all remaining destructors:
zend_objects_store_call_destructors(&EG(objects_store) TSRMLS_CC);
This will walk all objects (in order of creation) and call their destructor. Note that this only calls the "dtor" handler, but not the "free" handler. This distinction is internally important and basically means that PHP will only call __destruct, but will not actually destroy the object (or even change its refcount). So if other objects reference the dtored object, it will still be available (even though the destructor was already called). They will be using some kind of "half-destroyed" object, in a sense (see example below).
In case the execution is stopped while calling the destructors (e.g. due to a die) the remaining destructors are not called. Instead PHP will mark the objects are already destructed:
zend_objects_store_mark_destructed(&EG(objects_store) TSRMLS_CC);
The important lesson here is that in PHP a destructor is not necessarily called. The cases when this happens are rather rare, but it can happen. Furthermore this means that after this point no more destructors will be called, so the remainder of the (rather complicated) shutdown procedure does not matter anymore. At some point during the shutdown all the objects will be freed, but as the destructors have already been called this is not noticeable for userland.
I should point out that this is the shutdown order as it currently is. This has changed in the past and may change in the future. It's not something you should rely on.
Example for using an already destructed object
Here is an example showing that it is sometimes possible to use an object that already had its destructor called:
<?php
class A {
public $state = 'not destructed';
public function __destruct() { $this->state = 'destructed'; }
}
class B {
protected $a;
public function __construct(A $a) { $this->a = $a; }
public function __destruct() { var_dump($this->a->state); }
}
$a = new A;
$b = new B($a);
// prevent early destruction by binding to an error handler (one of the last things that is freed)
set_error_handler(function() use($b) {});
The above script will output destructed.
What is the exact order of deconstruction? Can anyone describe in detail the implementation of destruction order that PHP uses? And, if this order is not consistent between any and all PHP versions, can anyone pinpoint which PHP versions this order changes in?
I can answer three of these for you, in a somewhat roundabout way.
The exact order of destruction is not always clear, but is always consistent given a single script and PHP version. That is, the same script running with the same parameters that creates objects in the same order will basically always get the same destruction order as long as it runs on the same PHP version.
The shutdown process -- the thing that triggers object destruction when script execution has stopped -- has changed in the recent past, at least twice in a way that impacted the destruction order indirectly. One of these two introduced bugs in some old code I had to maintain.
The big one was back in 5.1. Prior to 5.1, the user's session was written to disk at the very start of the shutdown sequence, before object destruction. This meant that session handlers could access anything that was left over object-wise, like, say, custom database access objects. In 5.1, sessions were written after one sweep of object destruction. In order to retain the previous behavior, you had to manually register a shutdown function (which are run in order of definition at the start of shutdown before destruction) in order to successfully write session data if the write routines needed a (global) object.
It is not clear if the 5.1 change was intended or was a bug. I've seen both claimed.
The next change was in 5.3, with the introduction of the new garbage collection system. While the order of operations at shutdown remained the same, the precise order of destruction could now change based on ref counting and other delightful horrors.
NikiC's answer has details on the current (at time of writing) internal implementation of the shutdown process.
Once again, this is not guaranteed anywhere, and the documentation very expressly tells you to never assume a destruction order.
For anyone interested - as at PHP 8.0:
class A {
function __destruct() {
print get_class();
}
}
class B {
private $child;
function __construct() {
$this->child = new A();
}
function __destruct() {
print get_class();
}
}
class C {
private $child;
function __construct() {
$this->child = new B();
}
function __destruct() {
print get_class();
}
}
new C;
results in output of
CBA
ie. the containing object destructor fires before the contained object destructor.
To reverse the order if desired ie. to ABC, change the destructor in all but A (innermost class) to be:
function __destruct() {
unset($this->child);
print get_class();
}
I created a class implementing ArrayAccess and I added it a function to prevents WRITE actions:
$Obj->Add("key","something");
$Obj->Add("key2","something2");
$Obj->SetReadOnly(); // sets read only property
unset($Obj["key2"]); // throws error, object is readonly
But, i want to prevent unsetting object too:
unset($Obj);
I can do it?I hear suggestions.
Thanks for help!.
I can't imagine any situation where you would really want to do this. I can also imagine doing this will cause you serious problems at script termination when all objects are destroyed. The PHP manual says the following on throwing exceptions in destructors:
Note:
Attempting to throw an exception from a destructor (called in the time
of script termination) causes a fatal error.
The above statement implies that you can throw an exception if you're not in the script termination phase, so maybe the following is possible.
public function __destruct ()
{
if ($this -> isReadOnly ())
{
throw new Exception ('Class is read-only');
}
}
However, as the manual points out, this will trigger a fatal error during script shutdown.
I honestly can't see any point to wanting to prevent object destruction. It should be up to the programmer to manage object lifetimes.
unset() does not actually destruct an object, if that's what you're trying to prevent.
An object will only be destructed when all references to it have been unset or are no longer in scope. Even then it won't happen until the garbage collector runs.
So if you have some code that you are worried will molest your object, you've already done a good job of making it immutable with your read-only logic.
Let's say you have
$Obj = gotMyObjectSomehow();
and you need to pass it to a some other code you don't want to unset $Obj. As long as that code is called inside a function, there's nothing to be concerned about. If you call
someFunction($Obj);
and let's say that function unsets the parameter it's passed in
function someFunction($anObj) {
unset($anObj);
}
then your original $Obj variable will still be set.
The function creates a second variable referencing the original object and uses that in its own scope.
You can't control unsetting variable names, because those names are not technically a part of the object referenced. Consider the following:
$a = new MyObject();
$b = $a;
Now you have two references to the same object. There is no difference between using $a and $b, because in PHP objects are always used by reference (i.e. you don't have to do $b =& $a in the second line). So both $a and $b are essentially the same object; unsetting $a will not destroy the object, as well as unsetting $b won't destroy it; all references need to be unset before the object is destroyed.
I don't think you can do what you're asking for - it's not possible to prevent a variable being unset like that.
However, a comment of yours above set me thinking. You said:
.... idea if you want to prevent unsets system variables in a thirdparty extensions
So if I understand you right, your aim here is to ensure that while the thirdparty code (ie your software) is in use, all the variables associated with it remain in place?
Now you haven't specified much about what variables there are in this system. We see one object in the question, but presumably there must be more than that? I'm guessing you've got a bunch of things that tie together, right? It would help in these sorts of questions to provide a bit more context; the actual thing that you're asking for isn't possible, but with a bit of understanding about what you want to achieve, we could come up with alternatives.
Okay. So my suggestion: create your objects as Singletons. This is often frowned on by purists, but might work well for this situation, depending on exactly what you're doing. The beauty here is that you can encapsulate all access to the object inside class methods, meaning that the developer using your code doesn't have access to the master copy of the object in order to unset it.
A singleton works like this:
<?php
class mySingletonClass {
private static $masterObject=null;
public static function getInstance() {
if(!isset(self::$masterObject)) {
self::$masterObject = new self;
}
return self::$masterObject;
}
private function __construct() {
//your existing constructor, as it already exists, but marked as private.
}
//...and all the other methods as you already have them.
}
The class constructor method is private, so can only be accessed from methods within the class. Therefore, you can no longer do new classname(). The only way you can get an object of this class is to get it from the static getInstance() method. And the key thing here is that this method always returns the same copy of the object.
$obj = mySingletonClass::getInstance();
unset($obj);
$obj = mySingletonClass::getInstance(); //will give the exact same object as the first time.
You can unset it if you want, but the original object is still there and can still be accessed. Any of your other classes can use that getInstance() method to get the same copy of the same object from anywhere in the program. It's an indestructible global variable.
Singletons are often used for a program's main database connection object, but it might be a useful pattern for you here.
I hope that helps. It's about the only way I can think of to get close to what you want.