Why does calling a function within define() break my site? - php

The following breaks my site quite badly:
define('FOO', get_foo());
However, the following works fine:
define('FOO', 'BAR');

You can't use function in define, this is not good. Define is used to make constants. Constants must not be changed, must have the same value during all the time. Functions, like get_foo(), can return different values. Php thinks that you want to put changable value to the constant. Try to put the result if this function to the variable:
$foo = get_foo();

Because define() expects a value for the constant and not the returned value of a function:
The value of the constant; only scalar and null values are allowed.
Scalar values are integer, float, string or boolean values. It is
possible to define resource constants, however it is not recommended
and may cause unpredictable behavior.

Related

Why is the PHP globals variable not working as a argument in a function?

Wondered why the use of a GLOBALS variable is causing an error.
function makeNewPage($cpage = $GLOBALS['url']){
//some code here
}
See the manual:
The default value must be a constant expression, not (for example) a variable, a class member or a function call.
(Presumably, because they are determined at compile time and not run time).
Also
A function may define C++-style default values for scalar arguments

Why DEFINE in PHP can accept random values?

Constants can't accept expressions that make calculations. Why can I declare DEFINE with random_int(1,4) and not get a fatal error? In this case, the value of the constant will be different every time the page loads. Is this correct for the ideology of constants?
define('RANDOM_NUMBER', random_int(2,4));
It's ideology question. Why is this correct in PHP? And why can use the expression in DEFINE but not in constants?
Constants can't accept expressions that make calculations.
This is not true.
define may accept as second parameter expressions, included values returned from a called function.
The restrictions for the value parameter of define are (from the manual)
value
The value of the constant. In PHP 5, value must be a scalar value (integer, float, string, boolean, or NULL). In PHP 7, array values are also accepted.
Of course a constant cannot be defined twice.
And -if I understand your question- this is the "ideology" of constants.
As they are defined the value cannot be modified in another part of the script as it's constant.
Of course if the script is run a second time the constant can get a different value like in your case.
Worth mentioning this is different for Class Constants - constants you declare inside a class definition with the keyword const.
Due to language design/specifications
The value must be a constant expression, not (for example) a variable, a property, or a function call.
Because the define function only get the result of random_int(2,4) as parameter and has no way to understand if it was created in a random or in a deterministic way.
What the program really does is:
$temp = random_int(2,4);
define("RANDOM_NUMBER", $x);
That said, the define is used to define a constant for a request script, not necessarily a constant for all requests, so it does make sense that every different request has a different value for the defined constant.
The official php documentation states:
While it is possible to define resource constants, it is not
recommended and may cause unpredictable behavior.
The same will apply to any non scalar values assigned to a DEFINE constant. The PHP documentation states that:
The value of the constant. In PHP 5, value must be a scalar value
(integer, float, string, boolean, or NULL). In PHP 7, array values are
also accepted.

catch constants as type string

I have a function that takes a constant as string and would like to know if it is possible to obtain the value of the constant referent.
myFunction( "FETCH_ASSOC" )
the argument is related to PDO::FETCH_ASSOC
is this possible?
I'm putting together a class to work with the database, thanks
Yes, you can use the constant function.
Note that it has to be the full qualifier though. Like constant("PDO::FETCH_ASSOC"), not just constant("FETCH_ASSOC") (unless you want the constant named FETCH_ASSOC in the global namespace, not in the PDO class).

PHP - What is the default data type of any PHP variable?

PHP is loosely Typed Language but could someone tell me, What is the default data type of any PHP variable? What is its implicit data Type?
PHP's variables are dynamic, and change depending on the data inside them. So they have no datatype by default.
From the manual on 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.
So, they are what you make of them.
The OP understands that PHP is a loosely typed language and therefore the type of any initialized variable is determined by the data it holds; so read that way, the question then becomes What is the type of an uninitialized variable? - the answer to which is null
PHP doesn't generally allow you to declare variables without initializing them, there's no direct equivalent to:
Dim SomeVar
Therefore the only way to see that "default" data type is to evaluate either a variable that hasn't been set or a class member that holds no data.
1: A variable that hasn't been set
echo $someVar === null ? "NULL" : "NOT NULL"; //outputs NULL (and triggers a Warning)
2: A declared class member that holds no data
class Test {
public static $someVar;
}
var_dump(Test::$someVar); // outputs NULL
Therefore:
the type of any initialized variable is determined by the data it holds
the type of any uninitialized variable is null
Type Juggling
PHP does not require (or support) explicit type definition in variable declaration; a variable's type is determined by the context in which the variable is used. That is to say, if a string value is assigned to variable $var, $var becomes a string. If an integer value is then assigned to $var, it becomes an integer.
An example of PHP's automatic type conversion is the addition operator '+'. If either operand is a float, then both operands are evaluated as floats, and the result will be a float. Otherwise, the operands will be interpreted as integers, and the result will also be an integer. Note that this does not change the types of the operands themselves; the only change is in how the operands are evaluated and what the type of the expression itself is.
Source: http://www.php.net/manual/en/language.types.type-juggling.php

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