tags:

views:

338

answers:

3

I would like to define a class constant using a concatenation of an existing constant and a string. I can't predefine it because only scalars are allowed for predefining constants, so I currently have it as part of my constructor with a defined() function checking if it is already defined. This solution works but my constant is now unnecessarily global.

Is there a way to define a class constant at runtime in php?

Thank you.

+4  A: 

See the PHP manual on Class constants

The value must be a constant expression, not (for example) a variable, a property, a result of a mathematical operation, or a function call.

In other words, it is not possible. You could do it with runkit_constant_add but this sort of monkey patching is strongly discouraged.

Gordon
Consider using a static variable. http://php.net/manual/en/language.oop5.static.php
Matchu
is using define() considered monkey-patching? is there a reason why defining global constants at runtime is acceptable whereas defining class constants is not?
joshs
@josh Using define() *as such* is not considered monkey-patching. You have to have a mechanism to define constants and technically this always happens at runtime. However, the idea of such a constant is to provide a *globally available*, *fixed* value, which is why you usually declare constants on top of your script. Doing so later or based on some conditions is what I would consider wrong use because then you are using the constant like a variable and in case of or redefining or deleting them, I'd consider it bad monkeypatching, because it changes PHP's internal behavior.
Gordon
@gordon thanks for the explanation. in my example, my class constant was a concatenation of a base path (stored in another constant) and a string, thereby forming a new path. the path is fixed, but by using the existing constant, i preserved just one maintainable reference to the application base path. this seems like a fair use of a constant. ultimately i used a global constant and avoided changing the class constant at runtime, while still using a constant.
joshs
+1  A: 

Another option is to use the magic methods __get() and __set() to reject changes to certain variables. This is not so much a constant as a read-only variable (from the perspective of other classes). Something like this:

// Completely untested, just an idea
// inspired in part from the Zend_Config class in Zend Framework
class Foobar {

    private $myconstant;

    public function __construct($val) {
        $this->myconstant = $val;
    }

    public function __get($name) {
        // this will expose any private variables
        // you may want to only allow certain ones to be exposed
        return $this->$name;
    }

    public function __set($name) {
        throw new Excpetion("Can't set read-only property");
    }
}
MadCoder
A: 

You cannot do exactly what you want to do, per Gordon's answer. However, you can do something like this. You can only set it once:

class MyClass
{
    private static $myFakeConst;

    public getMyFakeConst()
    {
        return self::$myFakeConst;
    }

    public setMyFakeConst($val)
    {
        if (!is_null(self::$myFakeConst))
            throw new Exception('Cannot change the value of myFakeConst.');

        self::$myFakeConst = $val;
    }
}
ryeguy