Overriding class constants vs properties
Asked Answered
R

2

128

I would like to better understand why, in the scenario below, there is a difference in the way class constants are inherited vs. instance variables.

<?php
class ParentClass {
    const TEST = "ONE";
    protected $test = "ONE";

    public function showTest(){
        echo self::TEST;
        echo $this->test;
    }
}

class ChildClass extends ParentClass {
    const TEST = "TWO";
    protected $test = "TWO";

    public function myTest(){
        echo self::TEST;
        echo $this->test;
    }
}

$child = new ChildClass();
$child->myTest();
$child->showTest();

Output:

TWO
TWO
ONE
TWO

In the code above, ChildClass does not have a showTest() method, so the ParentClass showTest() method is used by inheritance. The results show that since the method is executing on the ParentClass, the ParentClass version of the TEST constant is being evaluated, whereas because it's evaluating within the ChildClass context via inheritance, the ChildClass member variable $test is being evaluated.

I've read the documentation, but can't seem to see any mention of this nuance. Can anyone shed some light for me?

Resurgent answered 28/11, 2012 at 20:12 Comment(3)
WTF? Constant overriding!? Do not do this! never!Banausic
@Banausic Indeed. Someone should communicate that to the developers of PHP. Or at least allow final...Mozellemozes
There are sure good enough use cases even for constant overriding :]Expire
I
255

self:: Isn't inheritance-aware and always refers to the class it is being executed in. If you are using php5.3+ you might try static::TEST as static:: is inheritance-aware.

The difference is that static:: uses "late static binding". Find more information here:

http://php.net/manual/en/language.oop5.late-static-bindings.php

Here's a simple test script I wrote:

<?php

class One
{
    const TEST = "test1";

    function test() { echo static::TEST; }
}
class Two extends One
{
    const TEST = "test2";
}

$c = new Two();

$c->test();

output

test2
Illuminism answered 28/11, 2012 at 20:22 Comment(8)
+ for mentioning static::.Kami
Awesome. Thanks for the clarification and for providing the additional information on late-static-bindings (which I have yet to digest).Resurgent
Since test() is not a static method, why not using $this::TEST with PHP5.3+?Calefacient
Hi @Calefacient - The goal of the example was to show that instance-level code executing in class One was retrieving static values from class Two. self::TEST would have returned "test1" where static::TEST returns the expected "test2" - Hope that helps, thanks for replying!Illuminism
Hi @DavidFarrell - Yes, I got the self:: / static:: difference but I don't get why using static:: instead of $this:: (not self::). Is there a difference between $this:: and static:: (since there is one between static::/$this:: and self::)?Calefacient
@Calefacient I've researched the best I can, and it appears that $this:: and $object:: behave similarly to static:: in relation to late-static-binding semantics. I'm not sure I see value in $this:: but $object:: seems interesting to me. Either way its good to know - Cheers!Illuminism
Just coming back to this almost 2 years later: I've started making a habit of using static:: extensively wherever I might have previously used self::. I wonder whether there's any downside to this. In fact, this is probably worthy of an SE question.Resurgent
So I've created a follow-up question: #26760831Resurgent
P
19

In PHP, self refers to the class in which the called method or property is defined. So in your case you're calling self in ChildClass, so it uses the variable from that class. Then you use self in ParentClass, so it wil then refer to the variable in that class.

if you still want the child class to override the const of the parent class, then adjust the following code in your parent class to this:

public function showTest(){
    echo static::TEST;
    echo $this->test;
}

Note the static keyword. This is uses "late static binding". Now you're parent class will call the const of your child class.

Phenica answered 28/11, 2012 at 20:19 Comment(1)
pro. static:: made job in abstraction instead of self::Descriptive

© 2022 - 2024 — McMap. All rights reserved.