Jort
Jort

Reputation: 1411

Check if constant was overridden in child class in constructor of parent class?

I have an abstract class which defines several constants. Most of these constants will not be overridden by any child classes, but one should be. I define this one constant as null in my abstract class, and in the child class I assign it a value. The constructor will be the same in all child classes as well, so I have added a check to see if the constant was assigned a value or not, and throw an exception if it was not defined by the child class.

Some simplified code to sketch my problem:

Parent abstract class:

abstract class ParentClass {
    const TEST_CONSTANT = null;

    public function __construct()
    {
        if (!defined(self::TEST_CONSTANT)) {
            throw new Exception("Please define TEST_CONSTANT!");
        }
    }

    abstract protected function someFunction();
}

Child class:

class ChildClass extends ParentClass {
    const TEST_CONSTANT = "value";

    protected function someFunction()
    {
        //some functionality here
    }
}

However, when instantiating ChildClass, the exception "Please define TEST_CONSTANT!" will be thrown, even though the constant was overridden. I understand that I can simply make it a mandatory parameter in the constructor, and set a member variable that way (which is probably the more logical/practical solution).

In my case, it might not make much sense to use a constant for this purpose, but I'd still like to understand why this does not work. It should be possible to override constants in child classes. Does this override simply not occur until after the constructor is called? Is my check incorrect? Would be nice to understand the logic and sequence of events at play here.

Upvotes: 1

Views: 1020

Answers (2)

Mark Baker
Mark Baker

Reputation: 212412

You need to pass the argument to defined() as a string:

if (!defined('self::TEST_CONSTANT')) {

Otherwise, you're testing for the existence of a global constant called null (not 'null' but an actual null, which is pretty meaningless).... if you're trying to identify whether a global constant called value is defined, then you might also want to consider static::TEST_CONSTANT instead, which will take the value of static::TEST_CONSTANT from the child class that you've instantiated ('value') and test to see if a global constant with the name value has been defined.

Upvotes: 4

Alex Blex
Alex Blex

Reputation: 37048

You need to use late static building to access static child properties (and constants) from parent class:

abstract class ParentClass {
    const TEST_CONSTANT = null;

    public function __construct()
    {
        if (!defined(static::TEST_CONSTANT)) {
            throw new Exception("Please define TEST_CONSTANT!");
        }
    }

    abstract protected function someFunction();
}

Saying that, overriding constants looks a bit unusual. I am curious about usecase why you need it at all.

Upvotes: 2

Related Questions