PHP - how to destroy object and objects it contains? - php

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.

Related

Does PHP garbage collect function-scoped objects after a call returns?

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.

Will this PHP script leak memory?

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.

php - Access outer class from an anonymous callback

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

PHP Static class variables, inheritance, and garbage collection

I am having some memory problems with a script that uses objects set up with inherited static variables like this.
class a
{
public static $a = "a";
}
class b extends a
{
private $instanceVar = 'hey';
private $otherVar = 'you';
public function DoStuff()
{
echo self::$a;
}
}
then code that uses the classes like this
while(condition)
{
$obj = new b();
$obj -> DoStuff();
unset($obj);
}
My question is, will unsetting obj trigger garbage collection and the unsetting of its instance variables since it also holds a reference to the the inherited static variable?
unset in this code doesn't bring anything.
With and without it the object will be successfully collected when it's possible.
will unsetting obj trigger garbage collection
Not it won't. Garbage collector will be called automatically when it makes sense.
since it also holds a reference to the the inherited static variable
It doesn't. Objects don't hold references to a static properties.
If you care so much about GC and have PHP >= 5.3.0 have a look to
gc_collect_cycles and garbage collection in general

prevents a class unsetting in php

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.

Categories