PHP Destructor | unset() VS overwriting object - php

I have learned from this SO question that the best way to destroy objects in PHP is to use unset.
I am wondering if I even need to destroy the object if I am essentially using the same var in a loop ...
foreach ($ids_array as $id) {
$O = new Object($id);
// stuff and things
}
Does this really use the same memory or am I unknowingly creating a bunch of objects and not destroying them?

If there's no variable left referring to an object, it will eventually get garbage collected. For that purpose it's irrelevant whether you unset the variable(s) or simply assign something else to them so they stop referring to the object.
IMO you should rarely use unset, you should rather write small functions which will automatically discard all variables in their scope when they return, which means things will get garbage collected automatically rather sooner than later and you don't need to worry much about it.

Related

How to destroy an object?

As far as I know (which is very little) , there are two ways, given:
$var = new object()
Then:
// Method 1: Set to null
$var = null;
// Method 2: Unset
unset($var);
Other better method? Am I splitting hairs here?
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 seems 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.
A handy post explaining several mis-understandings about this:
Don't Call The Destructor explicitly
This covers several misconceptions about how the destructor works. Calling it explicitly will not actually destroy your variable, according to the PHP5 doc:
PHP 5 introduces a destructor concept similar to that of other
object-oriented languages, such as C++. 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.
The post above does state that setting the variable to null can work in some cases, as long as nothing else is pointing to the allocated memory.
Short answer: Both are needed.
I feel like the right answer was given but minimally. Yeah generally unset() is best for "speed", but if you want to reclaim memory immediately (at the cost of CPU) should want to use null.
Like others mentioned, setting to null doesn't mean everything is reclaimed, you can have shared memory (uncloned) objects that will prevent destruction of the object. Moreover, like others have said, you can't "destroy" the objects explicitly anyway so you shouldn't try to do it anyway.
You will need to figure out which is best for you. Also you can use __destruct() for an object which will be called on unset or null but it should be used carefully and like others said, never be called directly!
see:
http://www.stoimen.com/blog/2011/11/14/php-dont-call-the-destructor-explicitly/
What is difference between assigning NULL and unset?
May be in a situation where you are creating a new mysqli object.
$MyConnection = new mysqli($hn, $un, $pw, $db);
but even after you close the object
$MyConnection->close();
if you will use print_r() to check the contents of $MyConnection, you will get an error as below:
Error:
mysqli Object
Warning: print_r(): Property access is not allowed yet in /path/to/program on line ..
( [affected_rows] => [client_info] => [client_version] =>.................)
in which case you can't use unlink() because unlink() will require a path name string but in this case $MyConnection is an Object.
So you have another choice of setting its value to null:
$MyConnection = null;
now things go right, as you have expected. You don't have any content inside the variable $MyConnection as well as you already cleaned up the mysqli Object.
It's a recommended practice to close the Object before setting the value of your variable to null.
In PHP you are not destroying an object, you are destroying a pointer to the object. It is a big difference.
In other languages you can destroy an object and all the other pointers will give you exceptions or rubbish, but it is not a case for PHP.
This is a simple prove that you cannot destroy an object, you can only destroy a link to it.
$var = (object)['a'=>1];
$var2 = $var;
$var2->a = 2;
unset($var2);
echo $var->a;
returns
2
See it in action here: https://eval.in/1054130
I would go with unset because it might give the garbage collector a better hint so that the memory can be available again sooner. Be careful that any things the object points to either have other references or get unset first or you really will have to wait on the garbage collector since there would then be no handles to them.

when do we need to create pass/call by reference function

I will always be in confusion whether to create pass/call by reference functions. It would be great if someone could explain when exactly I should use it and some realistic examples.
A common reason for calling by reference (or pointers) in other languages is to save on space - but PHP is smart enough to implement copy-on-write for arguments which are declared as passed-by-value (copies). There are also some hidden semantic oddities - although PHP5 introduced the practice of always passing objects by reference, array values are always stored as references, call_user_func() always calls by value - never by reference (because it itself is a function - not a construct).
But this is additional to the original question asked.
In general its good practice to always declare your code as passing by value (copy) unless you explicitly want the value to be different after the invoked functionality returns. The reason being that you should know how the invoked functionality changes the state of the code you are currently writing. These concepts are generally referred to as isolation and separation of concerns.
Since PHP 5 there is no real reason to pass values by reference.
One exception is if you want to modify arrays in-place. Take for example the sort function. You can see that the array is passed by reference, which means that the array is sorted in place (no new array is returned).
Or consider a recursive function where each call needs to have access to the same datum (which is often an array too).
In php4 it was used for large variables. If you passed an array in a function the array was copied for use in the function, using a lot of memory and cpu. The solution was this:
function foo(&$arr)
{
echo $arr['value'];
}
$arr = new array();
foo($arr);
This way you only passed the reference, a link to the array and save memory and cpu. Since php5 every object and array (not sure of scalars like int) are passed by reference internally so there isn't any need to do it yourself.
This is best when your function will always return a modified version of the variable that is passed to it to the same variable
$var = modify($var);
function modify($var)
{
return $var.'ret';
}
If you will always return to the passed variable, using reference is great.
Also, when dealing with large variables and especially arrays, it is good to pass by reference wherever feasible. This helps save on memory.
Usually, I pass by reference when dealing with arrays since I usually return to the modified array to the original array.

Freeing objects in PHP

I am new to OOP in PHP (normally write software). I have read that when an object goes out of scope it will be free'd so there is no need to do it manually. However, if I have a script like:
while ($var == 1) {
$class = new My_Class();
//Do something
if ($something) {
break;
}
}
This script will loop until $something is true which in my mind will create a lot of instances of $class. Do I need to free it at the end of each iteration? Will the same var name just re-reference itself? If I do need to free it, would unset() suffice?
Thanks.
When you assign a new instance to a variable, the old instance referenced by that variable (if any) has its reference count decreased. In this case the refcount will become zero. Since it is no longer referenced it will be automatically cleaned up.
From PHP 5.3 there is a proper garbage collector that can also handle circular references. You can enable it by calling gc_enable.
It shouldn't be necessary to unset() it in this context, as it will be overwritten on each iteration of the loop. Depending on what other actions are taking place in the while loop, it may be preferable to assign the $class outside the loop. Does $class change on each iteration?
$class = new My_Class();
while ($var ==1)
{
// Do something
}
Unless: the loop will be running a very long time; you anticipate a high number of concurrent users; or there are limited resources on the server (i.e. self-host, VPS/shared, etc), then you don't need to worry about it. In any scenario where the script won't be running for very long (less than 5 seconds), anything you try to do to free memory is going to be less effective than PHP's garbage collector.
That said, if you need to clear the reference (because of one of the aforementioned scenarios, or because you like to be tidy), you can set the variable to null or use the unset function. That will remove the reference and PHP's garbage collector will clean it up because there are no more references to it.

The advantage / disadvantage between global variables and function parameters in PHP?

sorry i'm a beginner and i can't determine how good a question this is, maybe it sounds utterly obvious to some of you.
if our use of these two below is the same which is better?
function doSomething ($var1,$var2,..){
...
}
OR
function doSomething (){
global $var1,$var2,..;
...
}
by our use I mean that I know that in the second scenario we can also alter the global variables' value. but what if we don't need to do that, which is the better way of writing this function? does passing variables take less memory than announcing global's in a function?
The memory usage is a paltry concern. It's much more important that the code be easy to follow and not have... unpredicted... results. Adding global variables is a VERY BAD IDEA from this standpoint, IMO.
If you're concerned about memory usage, the thing to do is
function doSomething (&$var1, &$var2,..) {
...
}
This will pass the variables by reference and not create new copies of them in memory. If you modify them during the execution of the function, those modifications will be reflected when execution returns to the caller.
However, please note that it's very unusual for even this to be necessary for memory reasons. The usual reason to use by-reference is for the reason I listed above (modifying them for the caller). The way to go is almost always the simple
function doSomething ($var1, $var2) {
...
}
Avoid using global variables, use the passing variables in parameters approach instead. Depending on the size of your program, the performance may be negligible.
But if you are concerned with performance here are some key things to note about global variable performance with regards to local variables (variables defined within functions.)
Incrementing a global variable is 2 times slow than a local var.
Just declaring a global variable without using it in a function also slows things down (by about the same amount as incrementing a local var). PHP probably does a check to see if the global exists.
Also, global variables increase the risk of using wrong values, if they were altered elsewhere inside your code.
Write it to take parameters. Maintainability is far more important than micro-optimization. When you take parameters, the variables can not be modified in unexpected places.
Although it is not good practice as long as you guarantee that the global is never written, but only read you will have the flexibility of paramaters.
As as alternative, you can pass one parameter (or two if it really goes with the function, like exp) and the rest in an array of option (a bit like jquery does).
This way you are not using globals, have some parameter flexibility and have clearly defined the defaults for each parameter.
function get_things($thing_name,$opt= array() {
if(!isset($opt["order"])) $opt["order"]= 'ASC';
}
Pass in parameters, avoid globals. Keeping only the scope you need for a given situation is a measure of good code design. You may want to look at PHP variable scope...
http://php.net/manual/en/language.variables.scope.php
An excellent resource, with some pointers on what is best practices and memory management.
As of PHP 4 using global with big variables affects performance significantly.
Having in $data a 3Mb string with binary map data and running 10k tests if the bit is 0 or 1 for different global usage gives the following time results:
function getBit($pos) {
global $data;
$posByte = floor($pos/8);
...
}
t5 bit open: 0.05495s, seek: 5.04544s, all: 5.10039s
function getBit($data) {
global $_bin_point;
$pos = $_bin_point;
$posByte = floor($pos/8);
}
t5 bit open: 0.03947s, seek: 0.12345s, all: 0.16292s
function getBit($data, $pos) {
$posByte = floor($pos/8);
...
}
t5 bit open: 0.05179s, seek: 0.08856s, all: 0.14035s
So, passing parameters is way faster than using global on variables >= 3Mb. Haven't tested with passing a $&data reference and haven't tested with PHP5.

Unsetting a variable vs setting to ''

Is it better form to do one of the following? If not, is one of them faster than the other?
unset($variable);
or to do
$variable = '';
they will do slightly different things:
unset will remove the variable from the symbol table and will decrement the reference count on the contents by 1. references to the variable after that will trigger a notice ("undefined variable"). (note, an object can override the default unset behavior on its properties by implementing __unset()).
setting to an empty string will decrement the reference count on the contents by 1, set the contents to a 0-length string, but the symbol will still remain in the symbol table, and you can still reference the variable. (note, an object can override the default assignment behavior on its properties by implementing __set()).
in older php's, when the ref count falls to 0, the destructor is called and the memory is freed immediately. in newer versions (>= 5.3), php uses a buffered scheme that has better handling for cyclical references (http://www.php.net/manual/en/features.gc.collecting-cycles.php), so the memory could possibly be freed later, tho it might not be delayed at all... in any case, that doesn't really cause any issues and the new algorithm prevents certain memory leaks.
if the variable name won't be used again, unset should be a few cpu cycles faster (since new contents don't need to be created). but if the variable name is re-used, php would have to create a new variable and symbol table entry, so it could be slower! the diff would be a negligible difference in most situations.
if you want to mark the variable as invalid for later checking, you could set it to false or null. that would be better than testing with isset() because a typo in the variable name would return false without any error... you can also pass false and null values to another function and retain the sentinel value, which can't be done with an unset var...
so i would say:
$var = false; ...
if ($var !== false) ...
or
$var = null; ...
if (!is_null($var)) ...
would be better for checking sentinel values than
unset($var); ...
if (isset($var)) ...
Technically $test = '' will return true to
if(isset($test))
Because it is still 'set', it is just set to en empty value.
It will however return true to
if(empty($test))
as it is an empty variable. It just depends on what you are checking for. Generally people tend to check if a variable isset, rather than if it is empty though.
So it is better to just unset it completely.
Also, this is easier to understand
unset($test);
than this
$test = '';
the first immediately tells you that the variable is NO LONGER SET. Where as the latter simply tells you it is set to a blank space. This is commonly used when you are going to add stuff to a variable and don't want PHP erroring on you.
You are doing different things, the purpose of unset is to destroys the specified variable in the context of where you make it, your second example simply sets the variable to an empty string.
Unsetting a variable doesn't force immediate memory freeing, if you are concerned about performance, setting the variable to NULL may be a better option, but really, the difference will be not noticeable...
Discussed in the docs:
unset() does just what it's name says
- unset a variable. It does not force immediate memory freeing. PHP's
garbage collector will do it when it
see fits - by intention as soon, as
those CPU cycles aren't needed anyway,
or as late as before the script would
run out of memory, whatever occurs
first.
If you are doing $whatever = null;
then you are rewriting variable's
data. You might get memory freed /
shrunk faster, but it may steal CPU
cycles from the code that truly needs
them sooner, resulting in a longer
overall execution time.
I think the most relevant difference is that unsetting a variable communicates that the variable will not be used by subsequent code (it also "enforces" this by reporting an E_NOTICE if you try to use it, as jspcal said that's because it's not in the symbol table anymore).
Therefore, if the empty string is a legal (or sentinel) value for whatever you are doing with your variable, go ahead and set it to ''. Otherwise, if the variable is no longer useful, unsetting it makes for clearer code intent.
They have totally different meanings. The former makes a variable non-existant. The latter just sets its value to the empty string. It doesn't matter which one is "better" so to speak, because they are for totally different things.
Are you trying to clean up memory or something? If so, don't; PHP manages memory for you, so you can leave it laying around and it'll get cleaned up automatically.
If you're not trying to clean up memory, then you need to figure out why you want to unset a variable or set it to empty, and choose the appropriate one. One good sanity check for this: let's say someone inserted the following line of code somewhere after your unset/empty:
if(strcmp($variable, '') == 0) { do_something(); }
And then, later:
if(!isset($variable)) { do_something_else(); }
The first will run do_something() if you set the variable to the empty string. The second will run do_something_else() if you unset the variable. Which of these do you expect to run if your script is behaving properly?
There is one other 'gotcha' to consider here, the reference.
if you had:
$a = 'foobar';
$variable =& $a;
then to do either of your two alternatives is quite different.
$variable = '';
sets both $variable and $a to the empty string, where as
unset($variable);
removes the reference link between $a and $variable while removing $variable from the symbol table. This is indeed the only way to unlink $a and $variable without setting $variable to reference something else. Note, e.g., $variable = null; won't do it.

Categories