0

I am experiencing something in PHP that seems very odd. I am trying to access a static property from a non static method. I need to use the static keyword to access this property as it can have different values in each child class.

However, instead of accessing a property from the expected class at all, it instead accesses the property from the calling class. This seems like a bug to me, but if it isn't, I was wondering if someone could explain this behaviour to me and also explain how I can access this static property.

My expectation here is that the static property $why would be taken from class B. I am perplexed as to why instead it would be taken from Class A.

<?php

error_reporting(E_ALL & ~E_STRICT);

class A
{
    public static $why = "Really don't want this value. Bug?";
    public function callB()
    {
        $B = new B;
        $B::getWhy(); // PHP Bug? 
        $B->getWhy();
        $B::getWhyStatic();
        $B::getWhyStaticSelf();
    }
}

class Base {

    protected static $why = "Don't want this value";

    public static function getWhyStatic()
    {
        echo static::$why . "<BR>\n";    
    }

    public static function getWhyStaticSelf()
    {
        echo self::$why . "<BR>\n";    
    }

    public function getWhy()
    {
        echo static::$why . "<BR>\n";
    }
}

class B extends Base
{
    protected static $why = "Want this value?";
}

$A = new A;
$A->callB();
Kenneth Spencer
  • 1,392
  • 12
  • 15
  • You need to be more clear with your question, for example, which property do you wish to access and which you access instead? – ollieread Dec 17 '13 at 20:33
  • Have added some additional clarification. Would appreciate removal of down vote. – Kenneth Spencer Dec 17 '13 at 21:13
  • Down vote removed, see my edited answer below, change `$B::bah()` to `$B->bah()` should fix it – ollieread Dec 17 '13 at 21:14
  • possible duplicate of [Calling non static method with "::"](http://stackoverflow.com/questions/3754786/calling-non-static-method-with) – ollieread Dec 18 '13 at 19:28
  • I don't think this is a duplicate. The above is asking why non static methods can be called statically at all. I am asking why, when they are called statically why the incorrect static property is returned. – Kenneth Spencer Dec 20 '13 at 21:59
  • It's not an incorrect value, see my answer below. – ollieread Dec 20 '13 at 22:04

2 Answers2

2

$B::bah(); should be $B->bah();, as bah is not a static function.

Kevin Ji
  • 10,479
  • 4
  • 40
  • 63
  • Yeah, I realize this. Am dealing with some legacy code where some formerly static methods have been converted to non static. While doing some cleanup I noticed this odd behaviour and got to wondering if there was a bug in PHP. If this is something one can't do, I would expect PHP to throw an E_ERROR instead of an E_STRICT. – Kenneth Spencer Dec 17 '13 at 19:35
2

This isn't really a bug, but more it's result that's not really covered in the documentation. I've done a bit of research and played with a few things myself and I think I've figured it out, but I can't be 100% certain as there's no official text covering this.

The impression that I get, is when you attempt to call a static method on an instance, it's the equivelant of using the class name, and PHP will actually call it that way, rather than of the instance. For example $B::getWhy(); is the same as B::getWhy(), which is how the core code will see it, whether you pass it an instance or not.

The issue you're having is that you're calling a non-static method as a static method. Because of the way methods work, they require a scope to provide such things as self and $this. Now, by calling the non-static method as if it was a static method, and taking into consideration the above about the way PHP will actually run the code, the only scope that is available is that of class A because that's the scope you're calling it from. This means that the late static binding takes place and overrides B::$why with A::$why because of the scope change, which is exactly what late static binding is supposed to achieve.

I hope that makes sense, if there are any bits that are unclear, let me know and I'll do my best to explain.

For more information, there's another question that actually tackles this: Calling non static method with "::"

Community
  • 1
  • 1
ollieread
  • 6,018
  • 1
  • 20
  • 36
  • Changing the original code does not explain the original behavior. And that has been asked for, I think. – Sven Dec 17 '13 at 19:35
  • Need the late static binding here, switching from static:: to self:: is not an option here unless self:: behaves differently in non static methods than static ones. – Kenneth Spencer Dec 17 '13 at 19:38
  • Why do you require late static binding? You need to add more information to your original post since `B` is not a child of `A`, instead they're complete independent classes. – ollieread Dec 17 '13 at 20:23
  • I've updated my example to one that hopefully more clearly illustrates the problem. – Kenneth Spencer Dec 18 '13 at 19:03
  • I've updated my answer, don't take it as gospel, but it's the only thing I can get that makes sense right now. – ollieread Dec 18 '13 at 19:23
  • This makes about as much sense as anything. Seems like the problem here is that PHP should throw an E_ERROR not an E_STRICT when using PHP this way – Kenneth Spencer Dec 20 '13 at 22:08
  • It's a tricky one, I can totally see why they didn't as it does actually follow the late static binding rules. It's 12 of 1, half a dozen of the other. – ollieread Dec 20 '13 at 22:09