简体   繁体   中英

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM