Re: Initializing constants once, with code?
| From: | tyson andre | Date: | Fri, 03 Jan 2020 00:09:31 +0000 |
| Subject: | Re: Initializing constants once, with code? | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-107965@lists.php.net to get a copy of this message | ||
> The problem with using constants is that the value is still hardcoded
> and if we later want to change to pulling the data from a config file
> we have to change all the code that uses those constants.
It's possible to work around this by using a unique constant name
and define('unique_name', $dynamicExpression)
(and const MY_CLASS_CONST = \unique_name;)
Maybe php could add something along these lines:
local const X = sprintf('In %s', $dynamicValue);
// Not supported in functions or loops.
// Translates internally to:
// if (defined('some_globally_unique_constant123af') ||
// !define('some_globally_unique_constant123af', X)) { throw ...; }
// use some_globally_unique_constant123af as X;
class MyClass {
const PUBLIC = X;
}
- php still needs to prevent recursion such as
const A = count(B); const B = array_fill(1, A, 'value');,
which is why the simplest approach would be one that eagerly evaluates dynamic expressions.
That's probably not the only way - maybe it could track all of the constants that
are in the process of being defined and cause an uncatchable fatal error if there was recursion.
- Right now, reading the value of a class constant can already emit notices or throw an Error
(undeclared constants)
the first time it gets evaluated
- Any approach should throw for results that contain cycles, objects, or references,
the same way define() warns.
The below ugly proof of concept shows that the php runtime can in a sense
defer evaluation of dynamic class constants to runtime (not recursively)
(assume errstr/errfile control what constant gets loaded).
This POC should not be used anywhere.
<?php
set_error_handler(function ($errno, $errstr) {
echo "Ignoring $errno: $errstr\n";
define(
'SOME_GLOBALLY_UNIQUE_CONSTANT',
sprintf('Hello, %s', $GLOBALS['globalVar'])
);
});
class MyTest {
const KEY = 'myKey';
const FOO = [
self::KEY => [[][0], SOME_GLOBALLY_UNIQUE_CONSTANT][1],
];
}
$globalVar = 'world';
echo "Fetching MyTest::FOO\n";
var_dump(MyTest::FOO);
/*
Output:
Fetching MyTest::FOO
Ignoring 8: Undefined offset: 0
array(1) {
["myKey"]=>
string(12) "Hello, world"
}
*/