PHP Calling self on a non-static method
Asked Answered
P

2

9

Why is the 'self'-call to a non-satic method in this example working?

class A{

    protected function aNonStaticMethod(){
        return __class__;
    }

    public function aEcho(){
        echo self::aNonStaticMethod();
    }
}

Thanks for explanation.

Parget answered 7/10, 2013 at 6:18 Comment(5)
As nearly everywhere described and shown in examples (eg php.net/manual/de/language.oop5.static.php) self is used in a static method context. I haven't found examples where self is used without a 'public/protected/private/final static function method()'. So may I further like to know, if that use shown above is wrong.Parget
self:: is not limited to static context. Neither is parent:: nor SomeParentClass::.Naaman
@Naaman because calling non-static method statically does not make sense in PHP version > 4 ... :-) also it won't be supported in future - check my answer :)Overlarge
@Overlarge Please be aware that I wrote Some**Parent**Class:: and not SomeClass::. That means the call to SomeParentClass::someMethod() is made from a non-static context that extends SomeParentClass. And this would be perfectly valid.Naaman
@Naaman I was referring to your "Why shouldn't it?" question :) Of course, logically, static calls for static things are for all context - I use it too :) However I've added a note about that to my answer :)Overlarge
O
7

Calling non-static method statically

Theoretically it should not work, but as this comment says:

There was no static keyword in php4 but php4 did allow for static calls. To maintain backwards compatibility this was left in when the static keyword was added in php5.

This comment is supported by this official php.net wiki:

This is already deprecated if the call occurs from an instance method. Not annotating methods as static is an obsolete PHP4-ism.

You really should not call non-static method statically - it does not make sense (if there is a static keyword).

Avoid calling non-static methods statically completely!

...because a) it is a bad approach and b) the PHP docs say:

Caution
In PHP 5, calling non-static methods statically generates an E_STRICT level warning.

AND

Warning
In PHP 7, calling non-static methods statically is deprecated, and will generate an E_DEPRECATED warning. Support for calling non-static methods statically may be removed in the future.

Using :: operator for non-static calls - may be a good approach!

As @Kontrollfreak pointed out and as this docs say the :: operator is not limited to static calls:

the double colon, is a token that allows access to static, constant, and overridden properties or methods of a class

So it is OK if you reference this way a method or properties from a parent class - which is not limited to a direct parent.

EDIT: do not mistake this for Fascade etc. software patterns!

During writing this answer I forgot to mention that there might be cases, when the call is static, but internally it is calling dynamic method - for more info see patterns like Facade or Singleton.
However do NOT mistake these with issue described above! (issue above is about using direct static call on dynamic thing that should be called dynamically, these patterns are about calling static methods statically, which then may dynamically invoke something dynamic (internally)).

Overlarge answered 11/3, 2016 at 10:34 Comment(7)
Even if you're not using self or parent, the double colon :: doesn't necessarily mean the call is (or should be) static. How else would you reference a method of a parent class that is not your direct parent? See what I mean: Sandbox ExampleNaaman
@Naaman Yes, that is true, but only in the way you've described, using it to call class' own non-static method/property is a bad approach :) But thank you for pointing that out - I've added this note to my answer :) Also I've removed the self/parent chapter - I know this approach, I just forgot about it, sorry :POverlarge
You write it's bad approach to use self:: on normal methods. Is that your opinion or can back that claim up?Naaman
@Naaman - I don't want to be missunderstood - using self:: is bad approach only if you reference class'-own ***non-***static method - it is explained in the first part of my answer, but also in the latter one - "static, constant and overriden..." - since calling class' own non-static-non-constant things is not overriding nor constant calling nor static calling - using :: operator itself does not fit into this definition, Calling "my own" non-static should be done through -> ... So answer to both of your questions is yes - I think so & docs support what I say.Overlarge
I think you're mixing the issues here. Yes, the docs say calling non-static methods statically is deprecated. But using self::someNonStaticMethod() isn't a static call. Using self:: is more specific than using $this->, as the former always refers to its origin class. I prepared another example with self:: and $this-> to show the difference.Naaman
@Naaman Well that is sort of overriding - but backwards - so you are right on this one - however it still does fit to what I said... What I mean is if you would really call your own not-overriden (in any way) method with :: - that whould be wrong.Overlarge
Indeed, it is a difference between $this-> and self:: for non static calls. However, even if it works, using it is a bad practice. When you extend a class, you expect that the functions you override will be used. An extended class should not behave in a way that is unpredictable. It hides multiple responsibilities behind the name of a function. It would be cleaner to just have a private method you call with this if you do not intend to have it overwritten. For those reasons, this language feature is unsafe to use, especially in a team, because it brings no real value, but adds complexity.Ersatz
A
8

In your simple example $this and self is interchangable. But be aware of the different method resolving when dealing with inheritance (i added static for completeness):

class A {
    protected function aNonStaticMethod(){
        return __class__;
    }

    public function selfEcho(){
        echo self::aNonStaticMethod();
    }

    public function staticEcho(){
        echo static::aNonStaticMethod();
    }

    public function thisEcho(){
        echo $this->aNonStaticMethod();
    }
}

class B extends A {
    protected function aNonStaticMethod(){
        return __class__;
    }
}

$b = new B();
$b->selfEcho(); // A
$b->staticEcho(); // B
$b->thisEcho(); // B
Assiut answered 23/1, 2014 at 15:43 Comment(0)
O
7

Calling non-static method statically

Theoretically it should not work, but as this comment says:

There was no static keyword in php4 but php4 did allow for static calls. To maintain backwards compatibility this was left in when the static keyword was added in php5.

This comment is supported by this official php.net wiki:

This is already deprecated if the call occurs from an instance method. Not annotating methods as static is an obsolete PHP4-ism.

You really should not call non-static method statically - it does not make sense (if there is a static keyword).

Avoid calling non-static methods statically completely!

...because a) it is a bad approach and b) the PHP docs say:

Caution
In PHP 5, calling non-static methods statically generates an E_STRICT level warning.

AND

Warning
In PHP 7, calling non-static methods statically is deprecated, and will generate an E_DEPRECATED warning. Support for calling non-static methods statically may be removed in the future.

Using :: operator for non-static calls - may be a good approach!

As @Kontrollfreak pointed out and as this docs say the :: operator is not limited to static calls:

the double colon, is a token that allows access to static, constant, and overridden properties or methods of a class

So it is OK if you reference this way a method or properties from a parent class - which is not limited to a direct parent.

EDIT: do not mistake this for Fascade etc. software patterns!

During writing this answer I forgot to mention that there might be cases, when the call is static, but internally it is calling dynamic method - for more info see patterns like Facade or Singleton.
However do NOT mistake these with issue described above! (issue above is about using direct static call on dynamic thing that should be called dynamically, these patterns are about calling static methods statically, which then may dynamically invoke something dynamic (internally)).

Overlarge answered 11/3, 2016 at 10:34 Comment(7)
Even if you're not using self or parent, the double colon :: doesn't necessarily mean the call is (or should be) static. How else would you reference a method of a parent class that is not your direct parent? See what I mean: Sandbox ExampleNaaman
@Naaman Yes, that is true, but only in the way you've described, using it to call class' own non-static method/property is a bad approach :) But thank you for pointing that out - I've added this note to my answer :) Also I've removed the self/parent chapter - I know this approach, I just forgot about it, sorry :POverlarge
You write it's bad approach to use self:: on normal methods. Is that your opinion or can back that claim up?Naaman
@Naaman - I don't want to be missunderstood - using self:: is bad approach only if you reference class'-own ***non-***static method - it is explained in the first part of my answer, but also in the latter one - "static, constant and overriden..." - since calling class' own non-static-non-constant things is not overriding nor constant calling nor static calling - using :: operator itself does not fit into this definition, Calling "my own" non-static should be done through -> ... So answer to both of your questions is yes - I think so & docs support what I say.Overlarge
I think you're mixing the issues here. Yes, the docs say calling non-static methods statically is deprecated. But using self::someNonStaticMethod() isn't a static call. Using self:: is more specific than using $this->, as the former always refers to its origin class. I prepared another example with self:: and $this-> to show the difference.Naaman
@Naaman Well that is sort of overriding - but backwards - so you are right on this one - however it still does fit to what I said... What I mean is if you would really call your own not-overriden (in any way) method with :: - that whould be wrong.Overlarge
Indeed, it is a difference between $this-> and self:: for non static calls. However, even if it works, using it is a bad practice. When you extend a class, you expect that the functions you override will be used. An extended class should not behave in a way that is unpredictable. It hides multiple responsibilities behind the name of a function. It would be cleaner to just have a private method you call with this if you do not intend to have it overwritten. For those reasons, this language feature is unsafe to use, especially in a team, because it brings no real value, but adds complexity.Ersatz

© 2022 - 2024 — McMap. All rights reserved.