35

It might be nice to be able to define a local constant within the scope of a function in PHP

This way anyone reading the function would know that that definition is final within the function and doesn't affect any external code

Something like this (Not valid syntax):

public function laughManiacally($count){
  const LAUGH = 'HA';

  for($i=0;$i<$count;$i++){
    echo LAUGH;
  }
};  

Or possibly (Again not valid):

...
final $laugh = 'HA';
...

Is there anyway to do this? And if not why not?

UPDATE

The way that JavaScript allows block level constant declaration is similar to the functionality I was searching for

function laughManiacally(count) {
  const LAUGH = 'Ha';

  for (let i = 0; i < count; i++) {
    console.log(LAUGH);
  }
}
1
  • 1
    This question gets the highest score for a reason. In the heat of the moment, doing a quick fix, your comparison should have read $access == $level, but you typed $access = $level, and in SQL, where your mind was 2 mins ago, that is a comparison. Oops, now everyone has $level access. The ability to set a constant within a class method would be nice to have. Commented Oct 16, 2024 at 21:20

4 Answers 4

17

You should have

echo name_of_class::LAUGH

Otherwise PHP will be looking for a global constant that was created with define().


followup:

You can also only define constants at the object level, e.g.

class foo {
   const BAR = 'baz';  // valid

   function foo() {
      const BAR = 'baz'; // invalid. can't define constants INSIDE a method.
   }
}
Sign up to request clarification or add additional context in comments.

4 Comments

still giving error, may be i am doing in a wrong way:-eval.in/654344 . correct me
Cool, that's what I experienced, but is there anyway to mark a local variable as read-only?
it's a local variable. it can't be accessed from "outside" the function, so what's the point of making it read only? If you want it read only, then don't write to it (except for initialization).
For the same reason I wouldn't use a public class variable as a class constant.. I want to stop myself and other team members from writing to it. I was also curios.. I guess commenting a local variable is probably as close as I'm going to get though!
13

No, there are no function-level constants in PHP. The closest thing is a class constant:

class A
{
    const LAUGH = 'HA';

    function laughManiacally($count)
    {
        for ($i=0; $i < $count; ++$i) {
            echo static::LAUGH;
        }
    }
}

$obj = new A();
$obj->laughManiacally(5);

Output:

HAHAHAHAHA

I have also tried final $laugh = 'HA';

The final keyword cannot be applied to class properties - only to methods.

1 Comment

I normally find the documentation doesn't specify things that aren't there.. and as a result it isn't easy to find rarely used constructs. I was primarily using those syntax attempts to demonstrate the kind of functionality I was hoping for.
5

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

Comments

0

I think you're confusing const with scope here.

function foo() {
    $x = 1;
}

I don't need to declare $x as a const because it's already scoped to just foo(). I would have to explicitly raise it to the global scope to use it elsewhere (which is a bad idea for many reasons). $x can be changed, but only if you do so within your function, or edit the code.

Ironically, constants set by using define are globally scoped, with const generally being global, provided you're using an autoloader

1 Comment

hmmm, could be wrong but I think they are more desiring the "read-only" and "reserved once" aspects of const. still this is an important insight as class const, global const and define are all effectively global constants. So even if you have to declare const in the parent scope of a function, effectively there's no real difference in PHP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.