Destroying an ArrayObject in PHP - php

I was looking for the __destroy() method in ArrayObject but found no implementation.
If I set the variable containing an ArrayObject to NULL, will it correctly destroy all the objects stored in it and free memory? Or should I iterate the ArrayObject to destroy each of the objects before unsetting it?

When you unset or null the ArrayObject only the ArrayObject instance is destroyed. If the ArrayObject contains other objects, those will only be destroyed as long as there is no reference to them from somewhere else, e.g.
$foo = new StdClass;
$ao = new ArrayObject;
$ao[] = $foo;
$ao[] = new StdClass;
$ao = null; // will destroy the ArrayObject and the second stdClass
var_dump($foo); // but not the stdClass assigned to $foo
Also see http://www.php.net/manual/en/features.gc.refcounting-basics.php

In PHP you never really have to worry about memory usage beyond your own scope. unset($obj) will work fine, in your case. Alternatively you could simply leave the function you're in:
function f() {
$obj = new ArrayObject();
// do something
}
And the data will be cleaned up just fine.
PHPs internal memory management is rather simply: a reference count is kept for each piece of data and if that's 0 then it gets released. If only the ArrayObject holds the object, then it has a refcount of 1. Once the ArrayObject is gone, the refcount is 0 and the object will be gone.

Related

The PHP unset doesn't clear the reference completely

I have a simple class and assign its instance to its static variable. When I unset the instance, not sure why it doesn't actual release the memory.
class Foo {
public static $app;
public function __construct() {
self::$app = $this;
}
}
$foo = new Foo;
unset($foo);
var_dump($foo);
var_dump(Foo::$app);
Result:
Warning: Undefined variable $foo in /var/www/index.php on line 16
NULL object(Foo)#1 (0) { }
Obviously, the static $app point to the itself instance, we have unset the instance but doesn't really clean the memory for this variable. Why did it happen? Are the instance of the $app and the $foo different ones?
$foo and Foo::$app point to the same object as you desire. Any changes in terms of object properties will reflect either way if you do it.
This is because they point to the same copy in the memory as expected. However, PHP maintains a refcount indicating how many references to that memory location is present.
So, when you use unset($foo);, it doesn't garbage collect that memory location(and the value inside it), but rather just decreases the refcount of it. This can be proved using debug_zval_dump and PHP achieves the refcount maintenance using copy on write mechanism as mentioned in the linked doc.
Hence, unsetting $foo doesn't destroy the object itself but rather just the refcount and removes the variable from memory since the object still holds other references.
Snippet:
<?php
class Foo {
public static $app;
public function __construct() {
self::$app = $this;
}
}
$foo = new Foo;
var_dump($foo === Foo::$app);
debug_zval_dump(Foo::$app);
$foo = 90;// variable modified, copy on write mechanism done internally for Foo::$app, refcount modified
debug_zval_dump(Foo::$app);
Online Demo
You've only unset a reference to an object of class Foo, and that object will get garbage-collected next time garbage collector runs.
Classes, once loaded, live in the memory until request is terminated, and so will their static properties. If they hold a pointer to an object, that object won't be garbage-collected. If you want to garbage-collect Foo::$app, you'll need to unset it too.

Get methods on a standard class?

Is there a way to get all the methods of an instantiated standard class object? I'm talking about an object that has some methods and properties on it, not a fresh stdClass object. ReflectionClass seems to work only on classes.
Try get_class_methods(), sounds like what you're describing, if I understand you correctly.
You can use get_object_vars to get a list of all of the properties, and then iterate over them (or array_filter them) and determine which of them is_callable:
$myClass = new StdClass;
$myClass->someFunc = function($a) {
return $a - 1;
};
$myClass->someProperty = 42;
$properties = get_object_vars($myClass);
$methods = array_filter($properties, 'is_callable');
I'm not sure if it's my 5.4.39 version of PHP or not, but using the above example and instead doing var_dump(get_class_methods($myClass)); as #Mike suggested returns an empty array.

PHP - how to destroy object and objects it contains?

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.

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

PHP 5 - serializing objects and storing their relationship

I am writing a fairly complex PHP applications where a single user action can trigger changes in many other sub-systems, and I'm contemplating using an observer pattern. However, I am wondering if I have to re-create all the objects involved.
Is it possible to while serializing objects to store their relationships? For example
$equipmentHandler = new EquipmentHandler();
$character = new Character();
$character->subscribeOnEquipmentChanged($equipmentHandler);
$_SESSION['character'] = serialize($character);
$_SESSION['subscriber'] = serialize($equipmentHandler);
Will the relationship be preserved after unserializing? Or do I have do lump them all into one object?
$cache['character'] = $character;
$cache['subscriber'] = $equipmentHandler;
$_SESSION['cache'] = serialize($cache);
Any advice would be appreciated.
(PS. The character data requires many DB requests to create and I am thinking of storing it by doing a write to cache and DB, but only read from cache policy, so it will be serialized anyway)
A relation will be kept, but it will be different than you expect. When you serialize two instances of Character that both refer to the same EquipmentHandler, you're going to get two separate instances of this EquipmentHandler, instead of the single one you expected. As this example illustrates:
<?php
echo "BEFORE SERIALIZE:\n";
class A { }
class B { }
$a = new A;
$b = new B;
$a -> b = $b;
$a2 = new A;
$a2 -> b = $b;
var_dump($a->b);
var_dump($a2->b);
echo "AFTER SERIALIZE:\n";
$a3 = unserialize(serialize($a));
$a4 = unserialize(serialize($a2));
var_dump($a3->b);
var_dump($a4->b);
The output of this is:
BEFORE SERIALIZE:
object(B)#2 (0) {
}
object(B)#2 (0) {
}
AFTER SERIALIZE:
object(B)#5 (0) {
}
object(B)#7 (0) {
}
Look for the number after the pound. This refers to the object ID within PHP. Before serializing both $a->b and $a2->b refer to an object with object ID #2: the same instance. But after the serialization they refer to object IDs #5 and #7: different instances.
This may, or may not, be a problem for you.
To restore the connection to one single B object, you're going to have to get a little tricky. You could use the __sleep() handler in A to flatten the actual reference to an INSTANCE of B to just a mentioning of B: "I had a reference to B". Then implement the __wakeup() handler using that mentioning of a B instance in A to acquire a single instance of a new B object.
BTW. The PHP session extension already does serializing automatically, no need for you to pre-serialize it yourself :)
According to the manual of the serialize function:
The value to be serialized. serialize() handles all types, except the resource-type. You can even serialize() arrays that contain references to itself. Circular references inside the array/object you are serializing will also be stored. Any other reference will be lost.
When serializing objects, PHP will attempt to call the member function __sleep prior to serialization. This is to allow the object to do any last minute clean-up, etc. prior to being serialized. Likewise, when the object is restored using unserialize() the __wakeup member function is called.
So I guess it is not possible unless you do something smart in the _sleep and _wakeup
Your actually have the solution in your question! More complex cases might need to make use of __sleep and __wakeup ... but given the information you provided, all you have to do is -- as you suggest -- "lump them all into one object".
Explanation
In an answer to a similar question, I said:
Serialization will maintain "relative" references. (Technically, there is no such thing as a relative reference in PHP, but its a good way to conceptualize it.)
If you collect your referenced and referencing variables in an array, serializing the array will save the reference relationship. It won't maintain the original reference, but will automatically recreate it in the context of the new array returned by unserialize. ... It works the same way for internal references in objects.
Example
// example objects
class A {}
class B {}
$a = new A();
$b = new B();
$b->a = $a;
// collect referenced and referencing objects in array
$cache = array( 'a' => $a, 'b' => $b );
// flatten and recreate cache (represents data stored & retrieved from db)
$cached = unserialize( serialize( $cache ) );
// overwrite local variables from cache
extract( $cached, EXTR_OVERWRITE );
Then, if you do var_dump( $a ); var_dump( $b->a );, notice in the output below how the object IDs for $a and for $b->a are both '3', indicating they both refer to the same instance of A.
object(A)#3 (0) {
}
object(A)#3 (0) {
}

Categories