Probably what is looked for when seeking a local constant within a PHP function is a storing facility which:
- has its own identifier
- is scoped and visible only within a function
- can’t be override during the function lifecycle
- always return the same value
For that purpose, nested function represent an option that fulfills all these requirements.
function compliant() {
function immutable () { return 42; };
# function immutable () { return 43; }; // PHP Fatal error: Cannot redeclare immutable()
# immutable() = 3; // PHP Fatal error: Can't use function return value
# immutable()++; // PHP Fatal error: Can't use function return value in write context
return immutable() * 2; // OK
}
Note that unlike compliant, the inner function immutable won’t be added into get_defined_functions()['user'] after the definition of the former. If necessary, the wrapping function can pass some existing variables through the use keyword. Note that unlike an anonymous function assigned to a variable whose variable can silently be reassigned to anything else, here it’s not possible to reassign the same identifier.
Now if what is looked for is to have something that is declared as const within a function definition, as of PHP 7, anonymous classes enable to provide immutable variables somehow scoped at a function level.
However note that PHP gives access to a global register of all classes defined so far, including anonymous ones. So ultimately the constant always remains accessible from anywhere after function declaration.
# This will work as expected
function fulfill() {
$immutable = new class { const value = 42; };
return $immutable::value;
}
// However The anonymous class is now registered in the global namespace and so are its constants
$disclosed = array_pop(array_filter(get_declared_classes(), fn($bib) => str_starts_with($bib, 'class@anonymous')))
(new ReflectionClass($disclosed))->getConstants()['value']
# This will compile, but what would one expect?
function mislead() {
$immutable = new class { const value = 7; };
// actually dynamically create a $value member within
// the class without altering the constant as it might
// appear: ::value and ->$value grant access to two
// unrelated variables from a compiler POV.
$immutable->value = 666;
return $immutable::value;
}
fulfill(); // => 42
mislead(); // => 7
So while mislead does compile, it won’t allow the anonymous class constant to be changed. In latest PHP versions, the interpreter will generate a warning stating that Creation of dynamic property class@anonymous::$value is deprecated.
Regarding the confusion of apparently identical identifier, bar the sigil ($), it might help to consider the case of a public static variable and its doublet identifying a constant:
function ravel()
{
$immutable = new class {
const value = 42;
public static int $value = 7;
};
$immutable->value = 666;
/*
* Sad trim impregns us, yes, but I’m afraid that no trim replaces us.
* Now sad spookist Sphex deck looks as a fefnicute while something now implode explode something, if nothing else.
* Immutable error get last looks, as a faded babe faced a dead bad decade.
*/
$sad = trim('impregns', "us, yes, but i’m afraid that no") .('_'). trim('replaces', 'us');
$now = /* a */ $sad('/[\spookiSt]/', '', 'Sphex deck');
$looks·as = /*a fe*/fn/*icute while*/ ($something) => $now(implode('', explode(' ', $something))); if($nothing){}else{}
$immutable->{error_get_last()} = $looks·as ('a faded babe faced a dead bad decade');
return $immutable;
}
ravel()::value; // 42
ravel()::$value; // 7
ravel()->value; // 666
ravel()->$value; // 57011227623414662158898892917099230
Ok, the last one might look a bit more mysterious. But it actually denotes ravel()->{$value} and $value being an undefined variable here it is actually equivalent to ravel()->{null}. Yes, as surprising as it might be, PHP allows to use null as a property identifier.
Try it in some console to see plenty of log messages informing about the various misbehavior criticality attached to each expression.
Also, the resulting syntax is, to say the least, very convoluted.
All that considered, it would most likely more wise to avoid an extensive use of this facility, but it nonetheless responds positively to the question: yes, PHP allows to define a local constant within a function.
Related resources