Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best workaround to create a PHP class constant from an expression?

I'd like to be able to do something like this:

class Circle {

    const RADIUS_TO_CIRCUMFERENCE = M_PI * 2;  // Not allowed

    private $radius;

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

    ...

    public function getCircumference() {
        return $this->radius * self::RADIUS_TO_CIRCUMFERENCE;
    }

}

But I can't create a class constant from an expression like that:

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


So my question is: What's the best workaround for this limitation of PHP? I'm aware of the following workarounds, but are there any others which are better?

1. Create a property

class Circle {

    private static $RADIUS_TO_CIRCUMFERENCE;

    private $radius;

    public function __construct( $radius ) {
        $this->radius = $radius;
        $this->RADIUS_TO_CIRCUMFERENCE = M_PI * 2;
    }

    ...

    public function getCircumference() {
        return $this->radius * $this->RADIUS_TO_CIRCUMFERENCE;
    }

}

I don't like this, because the value of $RADIUS_TO_CIRCUMFERENCE can be changed, so it's not really a "constant".

2. Use define()

define( 'RAD_TO_CIRCUM', M_PI * 2 );

class Circle {

    const RADIUS_TO_CIRCUMFERENCE = RAD_TO_CIRCUM;

    ...

    public function getCircumference() {
        return $this->radius * self::RADIUS_TO_CIRCUMFERENCE;
    }

}

This is better, since the value is truly constant, but the drawback is that RAD_TO_CIRCUM has been globally defined.

A digression

I don't understand how this can work. (Edit: I've tested it, and it does work.) According to the Handbook of PHP Syntax:

The const modifier creates a compile-time constant and so the compiler will replace all usage of the constant with its value. In contrast, define creates a run-time constant which is not set until run-time. This is the reason why define constants may be assigned with expressional values, whereas const requires constant values which are known at compile-time.

The manual confirms that "constants defined using the const keyword ... are defined at compile-time".

In this bug report from 3 years ago, a member of the PHP team wrote:

For the class constant we need a constant value at compile time and can't evaluate expressions. define() is a regular function, evaluated at run time and can therefore contain any value of any form.

But in my example above, the value of RAD_TO_CIRCUM is not known at compile-time. So what is the compiler putting for the value of RADIUS_TO_CIRCUMFERENCE?

I'm guessing that the compiler creates some kind of placeholder for the value of RADIUS_TO_CIRCUMFERENCE, and at run-time, that placeholder gets replaced with the value of RAD_TO_CIRCUM. Might this placeholder be a kind of resource? If so, maybe this technique should be avoided? The manual says: "It is possible to define constants as a resource, but it should be avoided, as it can cause unexpected results."

3. Create a method

class Circle {

    ...

    private static function RADIUS_TO_CIRCUMFERENCE() {
        return M_PI * 2;
    }

    public function getCircumference() {
        return $this->radius * $this->RADIUS_TO_CIRCUMFERENCE();
    }

}

This is my favourite workaround that I'm aware of. The value is constant, and it doesn't affect the global space.

Is there another workaround which is even better?

like image 827
TachyonVortex Avatar asked Aug 06 '13 11:08

TachyonVortex


1 Answers

As of PHP 5.6, you can use math expressions in PHP constants, so this would work:

const RADIUS_TO_CIRCUMFERENCE = M_PI * 2;

I encountered this thread because my environment wasn't configured properly (was set to PHP 5.4 by accident), so don't forget to check your PHP version.

like image 141
keisar Avatar answered Sep 18 '22 17:09

keisar