I often get PHP errors about a variable not defined. I'm also wondering what is best practice for setting session variables. Currently I'm doing this:
session_start();
if (!isset($_SESSION["myVar"]))
$_SESSION["myVar"] = "";
But this seems untidy to me. I know there is a PHP unset function, but what is the equivalent to simply set/define a variable into existence, without setting an initial value?
Php has dynamic variable allocation and typing. When a variable is first referenced within a program, memory is allocated for its use.
Meaning that unless you don't assign a value, a variable can't be declared, like say, in java.
Best way how to make sure you "declare" all your variables?
Assign them to null or empty string at the beginning of each function / method.
About session variables, I'd apply the same logic.
Related
Is it necessary to initialize / declare a variable before a loop or a function?
Whether I initialize / declare variable before or not my code still works.
I'm sharing demo code for what I actually mean:
$cars = null;
foreach ($build as $brand) {
$cars .= $brand . ",";
}
echo $cars;
Or
foreach ($build as $brand) {
$cars .= $brand . ",";
}
echo $cars;
Both pieces of code works same for me, so is it necessary to initialize / declare a variable at the beginning?
PHP does not require it, but it is a good practice to always initialize your variables.
If you don't initialize your variables with a default value, the PHP engine will do a type cast depending on how you are using the variable. This sometimes will lead to unexpected behaviour.
So in short, in my opinion, always set a default value for your variables.
P.S.
In your case the value should be set to "" (empty string), instead of null, since you are using it to concatenate other strings.
Edit
As others (#n-dru) have noted, if you don't set a default value a notice will be generated.
You had better assign it an empty string $cars = '';, otherwise (in case you have error reporting on) you should see a notice:
Notice: Undefined variable: cars
PHP will assume it was empty and the resultant string will be the same, but you should prefer not to cause an extra overhead caused by a need of logging that Notice. So performance-wise it is better to assign it empty first.
Besides, using editors like Aptana, etc, you may wish to press F3 to see where given variable originated from. And it is so comfortable to have it initialized somewhere. So debugging-wise it is also better to have obvious place of the variable's birth.
It depends: If you declare a variable outside a function, it has a "global scope", that means it can only be accessed outside of a function.
If a variable is declared inside a function, it has a "local scope" and can be used only inside that function.
(http://www.w3schools.com/php/php_variables.asp)
But it seems that the variable "cars" that you defined outside the function works for your function even without the global keyword...
I want to use a global variable setup where they are all declared, initialized and use friendly syntax in PHP so I came up with this idea:
<?
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
$GLOBALS['debugger'] = 1; // set $GLOBALS['debugger'] to 1
DEFINE('DEBUGGER','$GLOBALS["debugger"]'); // friendly access to it globally
echo "1:" . DEBUGGER . ":<br>";
echo "2:" . ${DEBUGGER}. ":<br>";
echo "3:" . $GLOBALS['debugger'] . ":<br>";
if (DEBUGGER==1) {echo "DEBUG SET";}
?>
generates the following:
1:$GLOBALS["debugger"]:
Notice: Undefined variable: $GLOBALS["debugger"] in /home/tra50118/public_html/php/test.php on line 8
2::
3:1:
How can there be an error with 2: when clearly $GLOBALS["debugger"] IS defined? And then not generate a similar notice with the test at line 10?
I think what I am trying to do is to force PHP to interpret a string ($GLOBALS["debugger"]) as a variable at run time i.e. a constant variable variable
Disclaimer: I agree with the comments, globals are generally a bad idea.
That said, there's a few questions here that are worth answering, and the concept of indirection is useful, so here goes.
${'$GLOBALS["debugger"]'} is undefined. You don't include the leading '$' when using indirection. So, the correct version would be define('DEBUGGER', 'GLOBALS["debugger"]').
But, this doesn't work either. You can only access one level down via indirection. So you can access the array $GLOBALS, but you can't access keys in that array. Hence, you might use :
define('DEBUGGER', 'debugger');
${DEBUGGER};
This isn't useful, practically. You may as well just use $debugger directly, as it's been defined as a global and will be available everywhere. You may need to define global $debugger; at the start of functions however.
The reason your if statement is not causing notices is because you defined DEBUGGER to be a string. Since you aren't trying to use indirection in that line at all, it ends up reading as:
if ("$GLOBALS['debugger']"==1) {echo "DEBUG SET";}
This is clearly never true, though it is entirely valid PHP code.
I think you may have your constants crossed a bit.
DEFINE('DEBUGGER','$GLOBALS["debugger"]'); sets the constant DEBUGGER to the string $GLOBALS["debugger"].
Note that this is neither the value nor the reference, just a string.
Which causes these results:
1: Output the string $GLOBALS["debugger"]
2: Output the value of the variable named $GLOBALS["debugger"]. Note that this is the variable named "$GLOBALS["debugger"]", not the value of the key "debugger" in the array $GLOBALS. Thus a warning occurs, since that variable is undefined.
3: Output the actual value of $GLOBALS["debugger"]
Hopefully that all makes sense.
OK, thanks to all who answered. I think I get it now, I am new to PHP having come form a C++ background and was treating the define like the C++ #define and assuming it just did a string replace in the precompile/run phase.
In precis, I just wanted to use something like
DEBUGGER = 1;
instead of
$GLOBALS['debugger'] = 1;
for a whole lot of legitimate reasons; not the least of which is preventing simple typos stuffing you up. Alas, it appears this is not doable in PHP.
Thanks for the help, appreciated.
You can not use "variable variables" with any of the superglobal arrays, of which $GLOBALS is one, if you intend to do so inside an array or method. To get the behavior you would have to use $$, but this will not work as I mentioned.
Constants in php are already global, so I don't know what this would buy you from your example, or what you are going for.
Your last comparison "works" because you are setting the constant to a string, and it is possible with PHP's typecasting to compare a string to an integer. Of course it evaluates to false, which might be surprising to you, since you expected it to actually work.
Say I've got a global variable which I'm accessing inside a PHP block, which compares to a querystring... if the comparison is true I want to set the value for a global EE variable so that all the other template pages can recognise that the value is not what it normally is - is this possible, or are the global user-defined variables constants?
Thanks,
Dan
$this->EE->config->_global_vars['foo'] = 'bar';
But keep in mind that the variable may have already been parsed before you have a chance to change it, depending on where and how it's used (see EE2's parse order discusssion).
You can use the PHP $GLOBAL Superglobal Array, for such cases. Say you have written a variable in any block of a particular page as $a = 123;.
Now in the same page, but in another block, you can easily change it to something else as $GLOBALS['a'] = 456;.
Hope it helps.
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.
According to many sources, register_globals (global variables that is) should be disables in your php.ini.
Should I write define() in my code and use constants if global variables are disabled? Are those even related?
They are related in that they have global scope, but constants are meant to not change once defined, unlike global variables which the page can modify as it goes along. So just switching over to using define() instead of a global won't help much.
It's better if you refactor your methods to take the variables as parameters and rely on that to pass variables around.
Global variables aren't constant (you can change the value of a global variable, but you can only define a constant once).
Constants aren't always global (you can declare a constant in a class).
Also, global variables can be any type: scalar, array, or object. Constants can only be scalars.
I'm not going to say either constants or globals are good or bad. When used appropriately, they both have beneficial uses. There are security issues around the register_globals feature that are separate from more general use of globals.
A few things here.
First, the register_globals that you disable in your php.ini refers to an old PHP feature where any variable sent via a query string (GET) or form (GET/POST) would be converted into a global PHP variable. This is the functionality that is (and should be) disabled when you turn off register_globals. Even with this off, you can still define global variables in your application.
In general programming terms, global variables (not PHP's register_globals) are considered "bad" because when you encounter one as a programmer, you have no idea what other parts of the application might be using or changing it, or what effect your changes to that global might have. Also, if you're defining a new global variable, there's a chance you're going to overwriting an existing variable that someone else is relying on. When variables are defined locally (in a single function, or in other languages a single block) you can examine the local scope and usually determine what a change to that variable will do.
Constants, on the other hand, never change. You define them once, and they stay defined and no one can change them. That's why having global constants is considered "less bad" than having global variables.
Constants, once defined, cannot be changed.
Don't use constants as variables. If you need to use variables within functions, pass them into the function itself. Use everything in the way it was intended to be used. Variables are variable and Constants are constant.
Some constant examples:
<?php
// Certainly constant
define('MINUTES_PER_HOUR', 60);
define('DOZEN', 12);
// Constant, but specific to this application
define('GREETING', 'Dear %s');
define('TIMEOUT', 30);
// Configurable, but constant for this installation
define('DATABASE', 'mydb');
define('IMAGES_DIRECTORY', '/tmp/images');
// Not constant, or some other reason why can't be constant
$user = $_POST['userid'];
$days_of_week = array('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su');
?>
Something else to consider -- constants can't store things like arrays or objects, whereas something defined to $GLOBALS can be any variable type. So in some cases, if you need something to be global but it can't be stored to a constant by using define(), you might want to use $GLOBALS instead.
Also, register_globals and $GLOBALS are NOT the same thing!
You can change the global variable inside the function if both have a same name, because local variable override the global variable but does not change the value of global variable outside.in constant if you want to use same name variable in different function that not allowed to you and give a error,because it define one time and used in all program and you can not change the value of this variable in any function or block it is fixed value .
Try this simple test:
fileA.php:
<?php
define('SOMEVAL', 2);
?>
fileB.php:
<?php
if(defined('SOMEVAL')) echo SOMEVAL;
else echo "SOMEVAL does not exists\n";
include 'fileA.php';
if(defined('SOMEVAL')) echo 'SOMEVAL='.SOMEVAL;
else echo "SOMEVAL does not exists\n";
?>
Then run fileB.php and you'll see that before you include fileA.php, SOMEVAL is not defined. So what this means is that before you define anything, it won't be visible to the script.