Can you undefine or change a constant in PHP? - php

Can you undefine or change a constant in PHP?

No. Constants are constant.
Reference: php.net/manual/language.constants.php

I know this is late to the game... but here is one thing that might help some people...
In my "Application.php" file (where I define all my constants and include in all my scripts) I do something like this:
if( !defined( "LOGGER_ENABLED" )){
define( "LOGGER_ENABLED", true );
}
So normally, every script is going to get logging enabled... but if in ONE particular script I don't want this behavior I can simply do this BEFORE I include my Application.php:
define( "LOGGER_ENABLED", false );

If you absolutely need to do this (although I wouldn't recommend it as others have stated) you could always use Runkit.
http://www.php.net/manual/en/function.runkit-constant-redefine.php
http://www.php.net/manual/en/function.runkit-constant-remove.php

No. Once a constant is defined, it can never be changed or undefined.

As not mentioned elsewhere, the uopz extension allows a constant to be deleted via uopz_undefine(), for PHP 5.4+.

The other posters are correct - you can't do this. But perhaps you can move your definition to the point where you know what the best value for the constant would be.
Perhaps you're defining constants in a big list:
define('STRING1','Foo');
define('STRING2', 'Bar');
define('STRING3', 'Baz');
and you want to change the value of STRING2 once you discover a condition. One way would be to defer the definition until you know the correct setting.
define('STRING1','Foo');
// define('STRING2', 'Bar'); -- wait until initialization
define('STRING3', 'Baz');
...
if (condition) {
define('STRING2', 'Bar type 2');
} else {
define('STRING2', 'Bar type 1');
}
The logic setting STRING2 could even be in a different file, later on in your processing.

Related

How To Parse a Constant in PHP

Is it possible to parse the contents of a constant in PHP?
For example,
define('WHO_AM_I', 'My name is $_SESSION['who_am_i'].'); // setup the constant string
echo eval(WHO_AM_I); // something like this -- but the eval() returns an error
Please note that I do not know the value of the _SESSION var until I actually use the constant later in the script stream.
Thanks.
AMENDED WITH REASON FOR WANTING TO DO THIS
I want to pull "hard coding" out of my script and give the user the ability to configure certain taxonomy in their site. So while I was doing this I also wanted to create a quasi-dynamic constant that I thought I might be able to parse later in the script.
If it can't be done...then it can't be done.
Don't shoot me for asking the question though.
A FINAL COMMENT TO AVOID ALL THIS CONFUSION
The purpose of my question has nothing to do with the eval() function. I am actually regretting having put it in there in the first place.
I put the eval() in the question simply to demonstrate to stackoverflow members that I did a bit if prep on my question rather than asking an open ended -- hey give me a solution without having offered any stab at it myself. So please disregard the eval().
All I want to know is can I somehow craft a define() in an way that makes the assigned value parse-able later in my script. That's it, that's all.
AMENDMENT C
I know I can do the following although I don't want to do it this way:
define('PARSE_ABLE_CONSTANT_PART_A', 'My name is ');
define('PARSE_ABLE_CONSTANT_PART_B', '.');
...later down the script road...
echo PARSE_ABLE_CONSTANT_PART_A . $_SESSION['who_am_i'] . PARSE_ABLE_CONSTANT_PART_B;
I just don't want to do it this way if I can make it slicker using an embedded var in the constant.
This seems really fishy, as other users have pointed out. You could do something like this if you wanted:
define('WHO_AM_I', 'echo \'My name is \'.$_SESSION[\'who_am_i\'];');
eval(WHO_AM_I);
This will always just echo the variable. You need to eval an expression afaik.
Just read your edit. I think you would be better suited with an .ini file, or maybe a static class with static properties. Makes it much more flexible, and you avoid the eval. You are talking user-generated content from what I can see - subjecting that to an eval call seems highly insecure.
A quick example of a static class you could use:
<?php
class myConstants{
public static function _($key){
switch($key){
case "WHO_AM_I":
return "My name is ".$_SESSION['who_am_i'];
break;
case "OTHER_CONSTANT":
// does some other evaluation and returns a string
break;
}
throw new Exception("Constant isn't defined");
}
}
?>
Then you can just echo myConstants::_('WHO_AM_I');
Constants by definition don't allow you to set it with dynamic content.
Here is a quote from the php manual:
As the name suggests, that value cannot change during the execution
of the script
You can see more by going here
You might be thinking of magical constants

Defining constants with $GLOBALS

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.

When and how to use Constants in PHP?

I'm currently programming a website (in PHP4). I plan to save values, which do not change during runtime, in constants. Those are for example the version number of login-data for the database.
Question 1: are there any (security relevant) problems that can arise from saving data in constants?
At the moment I do the following to define and call the constant:
define("VERSION", "1.0");
echo "Current version: ".VERSION."."; // Result: "Current version: 1.0."
There is one thing that annoys me: In case a constant is not defined, the "wrong" variable name is returned instead of e.g. NULL.
define("VERSION", "1.0");
echo "Current version: ".VERSIONXXX."."; // Result: "Current version: VERSIONXXX."
One solution I found to get an error message and the return value "NULL" when I accidently entered a wrong constant name is using the function constant():
define("VERSION", "1.0");
echo "Current version: ".constant("VERSIONXXX")."."; // Result: "Current version: ."
Question 2: Can I prevent in a different way, that PHP returns the name of the non-existing variable?
Question 3: Should the value of a constant in PHP always be returned using the function constant()?
If you attempt to use a constant that does not exist, PHP automagically assumes it is a string instead, which is why you see VERSIONXXX.
IIRC it throws a warning if you're error reporting is at the appropriate level. The best solution here is to ensure your code utilizes the proper constant names.
If you know the name of the constant, it's easiest/best to use it directly. echo MY_CONSTANT
If you don't know the name of the constant (e.g. it's name is in a variable), use constant():
$name = 'MY_CONSTANT';
echo constant($name);
In reverse Order:
Question 3: No
Question 2: Not really, but you can make adjustments.
because of (Question 1:) error_reporting. You PHP webserver is configured hide some errors. If you add
error_reporting(E_ALL);
to your scripts head, you will get a
Use of undefined constant MY_CONST - assumed 'MY_CONST'
Error. Unfortunately it's a problem coming out of PHP's long history, that constants can be interpreted as strings.
If you can not be shure a constant was set in the first place you can use defined
if(defined('MY_CONSTANT') {
//do something
}
But my personal opinion there shouldn't be many cases to need this, since the word constant alone implies a garanteed presence. The only exception I can think of is the typical header test.
if(!defined('MY_APP_IS_PRESENT')) {
die('You can not call this file on its own, please use index.php.');
}
And one last tipp: Go and make yourself a errorhandler function, maybe even with firephp?
Well, you could always use defined function to make sure the constant exists. Combined with a ternary statement, you could simply echo an empty string, something like:
echo defined( VERSION ) ? VERSION : "";
Not the best answer, but workable?
PHP manual for defined() is at http://php.net/manual/en/function.defined.php

Global vs. Define

I have a php file in which I need to be able to easily flip a switch. The switch is set to 1 for local server and 0 for production server. local_on='1'; or local_on='0';. Which way is better (creating a global or using define)? If either way is good which way is best practice?
define. You can't change its value later, and its value is always available in all scopes, tersely.
A global variable is, as its name indicates, variable -- which means its value can be changed by any portion of your code ; which, in your case, is probably not what you want.
On the other hand, a constant (that you'll set with define) is... well... constant ; and, as such, cannot be modified once set ; which is probably what you want, in your case.
Considering the variable vs constant idea, for this kind of switches, I generally use define() and constants.
The define is the better choice of the two, because global variables are bad news for reasons I'm sure you're already familiar with, and because you have to remember to declare global $var in every function and method in your code. Defined constants are automatically available everywhere. Additionally, a variable could inadvertently be set from one state to the other during the running of your script. This could cause some really hard-to-find bugs if it happened.
Another way that performs a little better than define symbols and minimizes name clashes is a class declaration like
abstract config {
const LOCAL = true; // toggle to false
// or maybe
const SERVER = 'local'; // toggle to 'remote'
// (maybe having if (config.SERVER == 'remote') would be more readable in some
// cases than if (!config.LOCAL) depends on your app)
}
I prefer define. Reasons:
You can't redefine it accidentally
You can use in other scope (ex. functions) without ugly $GLOBALS construction
PS: since PHP 5.3 you can use const , not only define to declare constants. It's more readable for me
Both work fine as long as you remember to choose a distinctive name (all-uppercase for defines) and use the modern way to access global variables via the $GLOBALS superglobal (sic). Also, global variables are, well, variable, so you could, in theory, change its value by accident or so.
To simplify deployment and not setting or unsetting the switch by accident, I'd recommend automatically setting it automatically by examining the properties of $_SERVER, like
// Turn on debugging code on local machine
define('MYPAGE_LOCAL_ON', $_SERVER['SERVER_NAME'] == 'my-dev-box');
Also, I don't see why you'd set the switch to a string or an integer for that matter. The boolean values true and false seem more appropriate.
In short terms, define is what you look for (for said reasons).
However, come the future development, you might look for something like a dependency for your whole application providing the context it is running in. This can not be done with constants, so then define but as well as global variables are both wrong.

PHP undefined constant testing

In PHP if I define a constant like this:
define('FOO', true);
if(FOO) do_something();
The method do_something gets executed as expected.
But if I don't define the BOO constant below:
if(BOO) do_something();
Then do_something also gets executed. What's going on here?
// BOO has not been defined
if(BOO) do_something();
BOO will be coerced into the string BOO, which is not empty, so it is truthy.
This is why some people who don't know better access an array member with $something[a].
You should code with error_reporting(E_ALL) which will then give you...
Notice: Use of undefined constant HELLO - assumed 'HELLO' in /t.php on line 5
You can see if it is defined with defined(). A lot of people use the following line so a PHP file accessed outside of its environment won't run...
<?php defined('APP') OR die('No direct access');
This exploits short circuit evaluation - if the left hand side is true, then it doesn't need to run the right hand side.
If you enable error logging, you'll see an error like the following:
PHP Notice: Use of undefined constant BOO - assumed 'BOO' in file at line N
What's happening is that PHP is just arbitrarily assuming that you meant to use 'BOO' and just forgot the quotes. And since strings other than '' and '0' are considered "true", the condition passes.
If it's not the existance of the constant you want to test, but if you want to test the value of the constant you defined, this might be a better way: if(BOO === true) or if(BOO === false)
if($FOO) do_something();
Just using FOO takes it as a value rather than the variable you defined. Better to use PHP's defined.
PHP is dynamically typed. You can achieve what you're trying to do with a function such as this:
function consttrue($const) {
return !defined($const) ? false : constant($const);
}
PHP will automatically make the guess that you meant the string format, which a string will return true.
However you should use the defined method:
bool defined ( string $name )
So it would be:
if(defined('BOO')) {\\code }
Another option is to use php's constant() function, as in:
if (constant('BOO')) doSomething();
Remember to enclose the constant's name in quotes.
Here is a PHP replit demonstrating the examples below.
Ap per the php docs, if the constant is defined, its value is returned; otherwise, null is returned.
Since null is falsey, this will behave as expected.
This can be used in cases where you need to know if something is explicitly defined as true (or at lease a truthy value) vs either not defined, or defined with a falsey value. This works particularly well when having a variable defined is the exception, or having it undefined could be a security risk.
if (constant('IS_DEV')) {
// *Remember to enclose the constant's name in quotes.*
// do stuff that should only happen in a dev environment
// By Default, if it didn't get defined it is, as though, 'false'
}
Using constant() when checking against variables is a good practice to mitigate against security risks in certain situations. For example, printing out php info only if a certain constant is (defined and) TRUE.
As your question shows, PHP's string conversion would expose details if somehow the constant did not get defined.
Alternately, you could:
if (defined('IS_DEV') && (IS_DEV)) {
// *Remember to enclose the constant's name in quotes for the FIRST operator.*
// do stuff that should only happen in a dev environment
}
Another method that would work is to use === or !==, which tests exact equality (including type), without performing typecast a conversion.
if (IS_DEV === true)) {
// do stuff that should only happen in a dev environment
}

Categories