Is there some assurance when __destruct is called, when considering simple objects without reference cycles? I know from java, that it is not defined when and if the function finalize is called, it depends on the garbage collector.
For example if you have a function like:
1 function test(){
2 $x = new SomeObject();
3 $y = new SomeObject();
4 $x = null;
5 }
Where SomeObject has no reference cycles.
Can you assume $x->__destruct is called at line 4 and $y->__destruct is called at line 5?
Testing the following script seems to indicate that this is true:
https://gist.github.com/KAYLukas/0b1d65e57b52862f8da5
Furthermore, SplFileObject seems to work on this predicate: it is impossible to close the file, instead you just need to set the variable to null. If this would not call __destruct directly it would be impossible to open the file reliable after it has been opened with SplFileObject.
I have found that there is an assurance that the __destruct will be called eventually, just not when.
Yes, you can assume that.
__destruct is always called at the moment where the last reference to the object disappears: when you can't access that object anymore in any way from the outside.
If there exist circular references, you need to wait until it circular garbage collector comes in, where it isn't defined at what point that happens.
If you have stored the object somewhere else too, you need to first remove it from there before the destructor is called.
For further information: Internal objects don't always destruct their resources upon __destruct (as the user might call it directly), but only when the object really is destroyed. (technical measure to prevent segfaults)
Also during shutdown, first variables and arrays are removed in the reverse order they were defined and where the last reference to an object disappears the object is destroyed. Then circular garbage collector comes in and removes the other objects and calls __destruct there.
The only thing which is undefined here, is the order in which the circular garbage collector removes objects and calls their __destruct function.
Related
I have a hard time understanding what SHOULD be done in a PHP class destructor
I'm coming from c++.
In c++, if I have this:
class A{
int n;
~A(){
}
}
class A2{
int* n;
~A2(){
delete n;
}
}
The language KNOWS that if an instance of A is out of scope, its member n should be deallocated, because n only belongs to that very instance.
BUT if an instance of A2 goes out of scope, it doesn't knows if the memory pointed by n should be deallocated (maybe there are other pointers out there pointing towards that same memory)
BUT, if we're sure we want to deallocate that memory IF A2 instance goes out of scope, we need to MANUALLY "delete" it, because its our intention.
What about php?
I'm a newcomer and I've seen several solutions:
class A3{
private $n;
public function __destruct(){
//Choice 1
unset($this->$n);
//Choice 2
delete $this->$n;
//Choice 3
}
}
I'm not sure of the difference between unset and delete, but whatever.
I was told (cf choice 3) that PHP does "by itself" deallocate the memory if we don't do anything.
But I don't then understand the use of delete or unset in the destructor.
We don't have the notion of "pointer" in php, so if an instance of A3 goes out of scope, it's natural to deallocate n.
so, is there anything that SHOULD be done in a destructor? If not, there is never a use of delete or unset in the destructor?
EDIT: rewritten code based on axiac comment
What do you write in the destructor in C++?
You probably write statements that release the resources acquired during the lifetime of the object, isn't it?
This is the same in PHP, but most of the times you don't need to put anything in the destructor because the unused memory and resources are automatically garbage-collected by the interpreter.
It is recommended, however, to release in the destructor the resources acquired in the constructor (or during the lifetime of the object) either to be sure the memory they use is freed earlier or as documentation: somebody that reads a destructor and finds a call to fclose() in it knows that in the constructor or maybe in another method of the class, a pairing call to fopen() was executed and the handler was stored inside the object.
P.S.
The line $n from:
class A3{
$n
public function __deconstruct(){
is incorrect. It should end with a semicolon (;) and if the intention is to declare a property the correct syntax is to start with one of the visibility specifiers (private, protected or public), like this:
class A3 {
private $n;
public function __destruct() {
The name of the destructor method is __destruct() and not __destructor().
There is no delete in PHP: http://php.net/manual/en/function.delete.php.
Your three choices are only one: choice #1 (unset($this->pdo);).
Read more about classes and objects in PHP. Start by forgetting most of what you know from C++ as PHP OOP works in a different way and your knowledge of C++ will probably make more harm than good on learning OOP in PHP.
I'm trying to debug a PHP memory leak. According to https://stackoverflow.com/a/29398380/2724978, PHP frees memory after function ends.. well, is that also valid for object functions?
My object has the following method:
function process All(){
$this->processA(); // intensive array processing - runs fine
$this->processB(); // intensive array processing - runs fine
$this->processC(); // intensive array processing - runs fine
$this->processD(); // intensive array processing - memory leak
}
Then I change to this:
function process All(){
$this->processD(); // intensive array processing - runs fine
}
So it appears that every function is piling up on the memory. Any ideas on how can I free it?
First, a clarification of terms (so that we're clear on what we mean when we say memory leak).
A memory leak is what happens when a program has allocated memory on the system that is no longer reachable by the program. This simply cannot happen as a direct result of your PHP code since PHP is solely responsible for managing your program's memory for you. Meaning that if a memory leak were to occur it would be a mistake made by PHP itself (the PHP memory manager) and not PHP code that you could have written. Only PHP extensions, which are written in C, and the PHP memory manager itself can leak memory. PHP code, cannot. I can assure you that the latter is exceedingly rare, if not impossible.
So according to this information, it is not possible for your PHP code to leak memory (period).
What you probably mean to say instead, is that you've either hit the user-defined PHP memory_limit or your code has a resulted in in OOM (Out of Memory) error. This is not what one would refer to as a memory leak, however. So it is crucially important that you include the actual OOM error along with your question in order to be able to decipher the problem with any degree of authority.
Because the answer you point to has to do with freeing local function variables, and the code you present as the problem, provides absolutely no indication that any local function variables are being used, it remains entirely unclear where memory is being allocated in the first place.
If I had to take a wild guess, I would say you're probably storing this array as an object property. Thus it remains in memory subject to any living reference of the object instance during that runtime.
The difference between a local variable and an instance property is that a local variable is destroyed after the function is finished. An instance property, however, is not destroyed until the object instance to which it belongs is destroyed. This doesn't happen until the last reference to that object is destroyed or you explicitly do so yourself.
class Foo {
protected $arr = [];
public function bar($baz) {
$this->arr[] = $baz; // object instance property
$quix = $baz; // local function variable
}
}
$foo = new Foo;
$foo->bar(1);
$foo->bar(2);
$foo->bar(3); // memory grows
In the above scenario the local variable $quix is always destroyed after each method call (this doesn't change whether you use a function or method, they are the same to PHP). However, the instance property $this->arr belongs to the object instance. So PHP cannot remove that from memory by itself until that instance $foo is destroyed or the script ends (implicitly destroys all memory).
I want to know when an object in PHP will be destruct (destroy) by default. For example if we instantiate a class in a function, does it destruct at the end of function or still will be alive ?
It will eventually be destroyed when all variables that point to the object cease to exist. Variables cease to exist when they go out of scope or when they are unset. Variables go out of scope when the scope/function they were declared in exits.
Yes, it will. The object will live for the duration that it's instance is in scope. You may wish to browse the PHP Garbage Collection documentation. It's also worth noting that you can try these things out for yourself by implementing a __destruct magic method.
I am writing a Proxy class in PHP.
To do so, I am using magic method to catch calls/get/set... to the proxied instance, and forward them to that instance.
However, I am unsure what to do in this situation:
class Proxy {
// Proxied object
private $instance;
// ...
function __destruct() {
// unset($this->instance); ?
// $this->instance->__destruct(); ?
// nothing ?
}
}
Should I (can I) call the destructor explicitly? Or should I just unset the object, knowing it won't really destroy it for sure (at least, immediately)?
Or should I just do nothing and wait for the garbage collector to destroy the instance?
Don't do anything. It'll be taken care of by the garbage collector, probably at around the same time as the proxy.
I highly suggest that you do not free the instance class when the proxy dies. I'm not sure how you do things in your codebase, but it is possible something will still hold a reference to your instance class. Safer to let GC take care of it. Destructors are rarely useful in PHP.
After taking a look at some old code:
//Nothing like a destructor!!
function destroy() {
settype(&$this, 'null');
}
And called by
$Cache->destroy();
However in PHP 5.3 I get
Deprecated: Call-time pass-by-reference has been deprecated in /blah/-cache-.php on line 154
How should I do this?
Your immediate problem can be met by removing the & in $this, but the whole construction doesn't make sense to me. If it's not plain invalid to destroy $this from within the object's context, it's definitely not good practice.
To destroy an object, a simple
unset($Cache);
will do.
If one wants to execute stuff when the object is destroyed, one should define a destructor in the class. (The comment in your destroy() code says that this is not the point here, though. :)
Just destroy the object like normal.
unset($Cache);
I don't know why they would do that nasty looking mess above. Keep in mind that if the object has pointers in different places you will need to unset all of them - not just that one line. (singletons are an example)
The error you're getting is not related to having a destructor. The error is simply because you've tried to pass $this by reference in a function call.
PHP used to allow this, but in current versions of PHP, if you want to pass something by reference, you should specify it in the function declaration.
Therefore, your function call should look like this:
settype($this, 'null');
(ie without the &). (btw -- the word 'null' in a string??? is that what you meant?)
And if you want to pass by ref, your function should look like this:
function settype(&$object, $secondparameter) {
...whatever the function does...
}
ie with the & in the function parameter.
This rule applies in all cases in PHP. As I said, it has nothing to do with your destructor method, or with it being an object; that's just how you pass by reference in modern PHP.
Now onto the other part of your question: A destructor method.
PHP does allow for an automatic destructor function, written within your class like this:
function __destruct() {
print "Destroying " . $this->name . "\n";
}
If you write this code, the __destruct() method will be called when the object is destroyed. This may or may not be what you want -- depends on how you want it to work. The object will be destroyed when all references to it are unset or come out of scope. If you're passing the object handle around by reference, this may not happen when you expect it to -- ie the object may persist in memory even when you say unset($myobject);. In this case, it may only actually get destroyed when the PHP program finishes running. If this is the case, and you need it to be called sooner than that, you may be fine continuing with the destroy() method you have already, and calling it explicity.
Hope that answers your question.