Drawbacks when using undefined constants as variables - php

Huh, don't know what to search for, therefore have no idea if this is a duplicate or not.
Example:
function foo($bar){
switch($bar)
case UNDEFINED:
return 'foo';
break;
case DEFINED:
return 'bar';
break;
default:
return 'no foo and no bar';
}
}
echo foo(DEFINED); # edited: had $ before function call
// bar
echo foo(OUTPUT);
// no foo and no bar
PHP (version 5.3) doesn't throw any errors, but are there any drawbacks to this?

Undefined constants are interpreted as strings. In your case these would be two strings "DEFINED" and "UNDEFINED". From the PHP manual:
If you use an undefined constant, PHP
assumes that you mean the name of the
constant itself, just as if you called
it as a string (CONSTANT vs
"CONSTANT"). An error of level
E_NOTICE will be issued when this
happens.
EDIT Ignoring E_NOTICE is considered to be bad style, this is from PHP documentation:
Enabling E_NOTICE during development
has some benefits. For debugging
purposes: NOTICE messages will warn
you about possible bugs in your code.
For example, use of unassigned values
is warned. It is extremely useful to
find typos and to save time for
debugging. NOTICE messages will warn
you about bad style. For example,
$arr[item] is better to be written as
$arr['item'] since PHP tries to treat
"item" as constant. If it is not a
constant, PHP assumes it is a string
index for the array.

Related

Warn on undefined array write

Let's preface this with an example of a script with typo:
$bc = getBaseConcept();
$bs['key'] = doOtherStuff($bc['key']);
return $bc;
Obviously in the middle line is a typo. It should be $bc instead of $bs. (And yes this was a legit typo of mine just minutes ago before writing this question)
This did not produce a warning.
So my question is: Is there a configuration option that lets this produce a warning?
Specifically: Writing to an array key of a name that was previously undefined.
E_ALL does not seem to help. This should not only generate the warnings for $bar but I want also a warning for $foo.
<?php
ini_set('error_reporting', E_ALL);
echo ini_get('error_reporting'), "\n";
$foo['bar'] = $bar['foo'];
32767
PHP Warning: Undefined variable $bar in Standard input code on line 4
PHP Warning: Trying to access array offset on value of type null in Standard input code on line 4
Unfortunately, php is not like other programming languages. If an unknown variable is used, PHP does the initialisation without complaining. Unfortunately, there is nothing you can do about this.
If you are using an IDE like phpstorm or netbeans the IDE will usually show a hint for uninitisalized variables.
It is not necessary to initialize variables in PHP however it is a
very good practice. Uninitialized variables have a default value of
their type depending on the context in which they are used - booleans
default to false, integers and floats default to zero, strings (e.g.
used in echo) are set as an empty string and arrays become to an empty
array.
https://www.php.net/manual/en/language.variables.basics.php

No E_NOTICE for undefined variables in array?

So.. I'm still confused by this, when creating an array with $array = array(); and then manually setting variables like:
<?php
$array[] = 1;
$array['type'] = 2;
$array['number'] = 3;
I know, this is OK for PHP to do, but then when I echo something like $array['none'] it won't show a E_NOTICE for undefined variables.
Can someone explain me, why?
It will. If you have turned on error reporting, it should display a warning similar to the one below:
Notice: Undefined index: none in /path/to/script.php line X.
To check, try the following:
<?php
ini_set('display_errors',1);
error_reporting(E_ALL);
$array = array();
echo $array['none'];
And, if you want to actually make sure they exist before trying to use them in your code, use isset():
if(isset($array['none'])) {
// do stuff ...
}
See it live!
All this is explained on the config doc page, too:
Enabling E_NOTICE during development has some benefits.
For debugging purposes: NOTICE messages will warn you about possible bugs in your code. For example, use of unassigned values is warned. It is extremely useful to find typos and to save time for debugging.
NOTICE messages will warn you about bad style. For example, $arr[item] is better to be written as $arr['item'] since PHP tries to treat "item" as constant. If it is not a constant, PHP assumes it is a string index for the array.
It's quite simple: When you access a key that doesn't exist, and assign it a new value, PHP will create that key, and add it to the list (or array). But when you try to access a non-existing key, and attempt to echo it's value, PHP won't crash, but it'll let you know that your code contains a possible bug:
$arr = array('foo' => 'bar');
echo $arr['fo'];
This issues a notice because my code may contain a typo. I may expect the key fo to exist, while clearly it doesn't, so I need to work on my code some more.
Another reason why this notice is issued is because lookups for non existing properties/keys are "slow". In order for PHP to know for a fact that the key doesn't exist, the entire array has to be scanned. That, too, is not ideal, though inevitable at times. If you have code that issues tons of E_NOTICE's, chances are that some simple if's, like:
if (!isset($arr['fo']))
{
$arr['fo'] = '';
}
echo $arr['fo'];
Will, though adding more code, effectively speed up your code. Not in the least because issueing notices isn't free (it's not that expensive, but not free either).
Other benefits:
Notices also let you know when you forgot to quote array keys, for example
echo $arr[foo];
echo $arr['foo'];
Initially, both will echo bar, but let's add 1 line of code to this:
define('foo', 'bar');
echo $arr[foo];
echo $arr['foo'];
This won't, because foo is now a constant, so $arr[foo] amounts to $arr['bar'];, which is an undefined index. Turning off notices, will just echo the string representation of NULL, which is an empty string.
Basically, notices help you. Use them, listen to them, and fix them. If your site is broken, fix it. If you get into the habbit of ignoring these notices, you'll probably set your ini files to a more "forgiving" setting, and grow lazy.
As time progresses, your code will become ever more messy/smelly, until such time you actually have a difficult to trace bug. You'll decide to turn your error reporting to E_STRICT | E_ALL, and won't be able to see the actual notice/warning that points out where your bug actually is, because your screen will be cluttered with E_NOTICE undefined index/variable...

Why do undefined constants evaluate to true?

Stupid question - I'm surprised this one has bitten me. Why do undefined constants in PHP evaluate to true?
Test case:
<?php
if(WHATEVER_THIS_ISNT_DEFINED)
echo 'Huh?';
?>
The above example prints 'Huh?'
Thanks so much for your help! :)
Try defined('WHATEVER_THIS_ISNT_DEFINED')
When PHP encounters a constant that is not defined, it throws an E_NOTICE, and uses the constant name you've tried to use as a string. That's why your snippet prints Huh!, because a non-empty string (which is not "0") will evaluate to true.
From the manual:
If you use an undefined constant, PHP
assumes that you mean the name of the
constant itself, just as if you called
it as a string (CONSTANT vs
"CONSTANT"). An error of level
E_NOTICE will be issued when this
happens.
If you set your error reporting level to report E_NOTICEs, which is a good practice during development, you will also see the notice thrown.
PHP Constant Syntax
defined()
Casting to Boolean
error_reporting
error_reporting() function
From the manual:
If you use an undefined constant, PHP assumes that you mean the name of the constant itself, just as if you called it as a string (CONSTANT vs "CONSTANT").
Basically, if WHATEVER_THIS_ISNT_DEFINED isn't defined, PHP interprets it as "WHATEVER_THIS_ISNT_DEFINED". Non-empty strings evaluate to true, so your expression will always pass (unless WHATEVER_THIS_ISNT_DEFINED is defined and set to a falsey value.)
This is, frankly, stupid behaviour. It was implemented, I believe, to allow things like $foo[bar] to work when the programmer should have used $foo['bar']. It's illogical behaviour like this that makes people think PHP isn't a real programming language.
The way to test whether a constant is defined is with defined.
Undefined constants are treated as strings by PHP: docs. Taking that fact, think it through in English language:
If "WHATEVER_THIS_ISNT_DEFINED", then do something.
... it is logical that it is "true" - you aren't comparing anything to anything else.
That is why, when doing if statements, it is best practice to include a specific evaluation. If you're checking for false, put it in the code: if (something === false) vs if (something). If you're checking to see if it is set, use isset, and so on.
Also, this highlights the importance of developing with notices and warnings enabled. Your server will throw a notice for this issue:
Notice: Use of undefined constant
MY_CONST - assumed 'MY_CONST' in
some_script.php on line 5
Turn on notices and warnings to develop, turn them off for production. Can only help!
Try defined(). If it's not defined then the constant assumes it's simply text.
Note that constant name must always be quoted when defined.
e.g.
define('MY_CONST','blah') - correct
define(MY_CONST,'blah') - incorrect
also
<?php
if (DEBUG) {
// echo some sensitive data.
}
?>
and saw this warning:
"Use of undefined constant DEBUG - assumed 'DEBUG'"
A clearer workaround is to use
<?php
if (defined('DEBUG')) {
// echo some sensitive data.
}
?>
See http://php.net/manual/en/language.constants.php
It's not just constants, it is a much broader issue with PHP's parsing engine. (You ought to see warnings in your logs.)
In PHP, "bare words" that it doesn't recognize are generally treated as strings that happen to be missing their quotes, and strings with a non-zero length tend to evaluate to true.
Try this:
$x = thisisatest ;
$y = "thisisatest";
if($x == $y){
echo("They are the same");
}
You should see "They are the same".
Old question, but in addition to defined() you can also use strict type checking using ===
<?php
if(WHATEVER_THIS_ISNT_DEFINED === true) // Or whatever type/value you are trying to check
echo 'Huh?';

PHP: just saying $someVariable; inside a function - does this do anything

I'm working on some PHP code (that I didn't write). Here and there inside functions there's stuff like this:
$foo;
if ($someCondition) {
$foo="some value";
}
return $foo;
Just checking: that first $foo; on a line by itself - it has no effect whatsoever, right?
This is debug code left over from PHP3 or PHP4. These versions generated an E_NOTICE for just mentioning a variable (it was implicitly a read access):
$undef; // E_NOTICE
PHP5 however does not treat it as variable access anymore. So it goes ignored.
PHP3: Warning: Uninitialized variable or array index or property (undef)
PHP4: Notice: Undefined variable: undef
PHP5: silence
Your right. Maybe original developer come from another language and "declare" used vars.
Another way to write this code snippet is
if ($someCondition) {
return "some value";
}
return null;
It would have some impact if it were:
global $foo;
But in the form you posted, it is irrelevant.
Right, no need for it at all. Some languages require a variable to be declared, not PHP.
In PHP, you can even concatenate into an undeclared variable. PHP is the loose hipster of the programming world. Anything goes, man.
I would guess it's lazy instantiation. I'd change the line to $foo = "", which should have the same effect;
I wonder if they think that its the equivalent to defining a variable to prevent errors when strict error reporting is enabled - although it actually doesn't (define the variable) when its written like that

When to use or not use symbols in PHP

I'm reading a PHP book where the author says that symbols should be avoided except when it's valid to use them. Very informative stuff, if he could only elaborate or give code examples but he doesn't.
Can someone from the experienced PHP bunch give me an example of what these symbols are, and when it makes sense to use them or not. I'm looking for a code example that I can wrap my head around since I don't quite get it in plain English. Code is more plain English to me.
Edit:
He says you can define a string as a 'symbol' which will make this string global and constant, but it's good for security since it's constant and can't be changed by mistake or intentionally. I'm looking for concrete examples of when those symbols are used.
I assume you mean Constants?
One big reason against using those in PHP is the fact that if a constant was not defined, PHP will interpret it as a string value and throw only a notice, not a fatal error as it - in my humble opinion - should.
define("NUMBER_OF_PAGES", 1);
echo NUMBER_OF_PAGES; // outputs "1"
echo NUMBR_OF_PAGES; // outputs literally "NUMBER_OF_PAGES" and throws
// Notice: Use of undefined constant NUMBR_OF_PAGES -
// assumed 'NUMBR_OF_PAGES' in xyz
// constant() is a workaround but it takes away a lot
// of a constant's elegance IMO:
echo constant("NUMBER_OF_PAGES"); // Returns "1"
echo constant("NUMBR_OF_PAGES"); // Returns null
this makes the use of constants somewhat error-prone, especially in older applications that trigger dozens or hundreds of E_NOTICE messages by using less-than-perfect coding practices (but nothing anywhere near as bad as using an undefined constant) and make it hard to detect errors.
The cleaner your application, the less of a problem this becomes, because dealing with (and noticing) E_NOTICE level messages becomes possible. Still, an undefined constant should be a fatal error in my mind, and I regard this a design error.
IDEs with lookup functions can ease the problem somewhat, and help avoid typos.
There is also the function constant() that will return NULL if given a non-existent constant name. (See the code above.)
Concrete usage examples:
WordPress list of constants
Joomla constants
Constants are often used to define the current path and / or URL:
define("APP_WEBROOT", "http://www.mydomain.com/appname");
define("APP_WEBROOT_PATH", "/var/www/mydomain/appname");
or to define global settings:
define("MAX_PAGES", 100);
define("MAX_ITEMS_PER_PAGE", 250);

Categories