Phpinspectionsea: You should use static instead of self

Created on 28 Jul 2017  路  7Comments  路  Source: kalessil/phpinspectionsea

I need help here.

Can we uses static instead of self in all cases? I mean, an inspection that check if you are using 麓self::ownMethod()and suggests to modify tostatic::ownMethod()`. It changes the behaviour for child classes, but the question is: it should be the real expected behaviour?

What is in my mind: using self can causes problem when you override a method on a child classes, because the method overridden will not be used, but the original method (https://3v4l.org/AS45q).

My suggestion here, _if it not cause any new problem_, is:

  • Suggests static instead of self if method is not-final;
  • Suggests self instead of static if method is final (once that static will not make any sense - or just always suggests static usage);

self is used to same-class referencing, but when it is really useful?

For now, I just imagine the use of self::class to check if $var is child-instance of a parent class, but it could works like an expection to rule (when used on is_a(), for instance) or just suggest to use __CLASS__.

Discussing here too: https://stackoverflow.com/questions/45396661/when-using-self-over-static

enhancement question wontfix easy-to-pick

Most helpful comment

Quote 1: _Can we use static:: instead of self:: in all cases?_

So, that is the question. I know that it will change the "caller" reference (and it _could_ change the behaviour), but the question is: _could we do that without broken any code?_ (replacing ALL self:: by static::, for instance) See: when I use self:: I do force my class to call the _own class method implementation_, even if I call it from a child class that _overriden this method implementation with a new one_. Then... can we think in a real case where it is really expected? I mean, it seems like a code failure and is hard to identify this problem (it was the cause of I create this issue).

Quote 2: _Suggests static:: instead of self:: if method is not-final_

By default, all classes and methods are opened for overriding. The final keyword block it forcefully, so a child class cannot override a method or class when is intentional that the parent class uses exactly a specific implementation. Then this argument is additional for the previous: if I have no intention to modify my class/method to have the modifier final, then I should be _okay_ for overriding, right? In this case, no make sense my class/method be opened to overriding but I keep using self:: (that is closed for overriding) instead of static:: (that is opened).

Quote 4: _self:: is used to same-class referencing, but when it is really useful?_

Right... But if you _really wants_ that the method behavior not be modified by child class, why it is not a final method? Why your method is opened for overring (not-final), but at same time you don't uses the overrided method (self:: instead of static::)?

You can say that in some places you uses self::sameMethod() and on same class you uses static::sameMethod() because of the expected behaviour for different contexts. But if self::sameMethod() could not be overrided, why you not creates a new private static final method to handle it separately? (So you can keep both behaviour intentionally.)

All 7 comments

Can we use static instead of self in all cases?

Nope, that changes semantics: static will refer to the caller-class (if I don;t miss anything).
And self ensures that specified method called, whatever happens in inheritance.

Suggests static instead of self if method is not-final

This opens the method for using overridden methods, we shouldn;t do this.

Suggests self instead of static (final class/method)

This is totally ok

self is used to same-class referencing, but when it is really useful?

To implicitly say: "Overrides in children must be ignored here, I work only in current class scope (incl. parents)"

self::class, just suggest using __CLASS__

This is also totally ok (as an extension of the "Constant can be used" inspection).

Quote 1: _Can we use static:: instead of self:: in all cases?_

So, that is the question. I know that it will change the "caller" reference (and it _could_ change the behaviour), but the question is: _could we do that without broken any code?_ (replacing ALL self:: by static::, for instance) See: when I use self:: I do force my class to call the _own class method implementation_, even if I call it from a child class that _overriden this method implementation with a new one_. Then... can we think in a real case where it is really expected? I mean, it seems like a code failure and is hard to identify this problem (it was the cause of I create this issue).

Quote 2: _Suggests static:: instead of self:: if method is not-final_

By default, all classes and methods are opened for overriding. The final keyword block it forcefully, so a child class cannot override a method or class when is intentional that the parent class uses exactly a specific implementation. Then this argument is additional for the previous: if I have no intention to modify my class/method to have the modifier final, then I should be _okay_ for overriding, right? In this case, no make sense my class/method be opened to overriding but I keep using self:: (that is closed for overriding) instead of static:: (that is opened).

Quote 4: _self:: is used to same-class referencing, but when it is really useful?_

Right... But if you _really wants_ that the method behavior not be modified by child class, why it is not a final method? Why your method is opened for overring (not-final), but at same time you don't uses the overrided method (self:: instead of static::)?

You can say that in some places you uses self::sameMethod() and on same class you uses static::sameMethod() because of the expected behaviour for different contexts. But if self::sameMethod() could not be overrided, why you not creates a new private static final method to handle it separately? (So you can keep both behaviour intentionally.)

Quote 1: Can we use static:: instead of self:: in all cases?

No

class  A {
 const DF = 123;
 public function printIt(){
  echo self::DF;
 }
}
class B extends A{
 const DF = 44;
 public function printOther(){
  echo self::DF;
 }
}

If we change self to static then we will have different result (new B())->printIt()
I do not prefer static it is better to use methods if we want to overwrite some logic.

Suggests static:: instead of self:: if method is not-final

We can break some code. Keep in mind that constants have visibility.
```php
class A {
private const DF = 123;
public function print1(){
echo static::DF;
}
}
class B extends A{
private const DF = 123;
}

Run `(new B())->print1();`

> Quote 4: self:: is used to same-class referencing, but when it is really useful?

Developers ignore important keyword `final`. 
My internal rules, maybe they can help you:
1. Use `static` keyword only for named constructors `public static function createWithUser(User $user)`
In other cases i do not use it. 
`public static $ids = []`  <- NOT
`public static function getDefault()`  <- NOT ;)
`static::someMethod()`  <- NOT 
2. Try to make all public methods `final` but keep open `constructors` 
```php
class User implements UserIntrface {
  private function __construct($id, $name){}
  public static function create(int $id) : User{}
  public static function createInMemory(int $id) : User{}
  public final function getName(){ }
  public final function getId(){ }
}

So in general i prefer to use self and against static keyword ;)

Thanks for reply!

I will try develop this inspection (_simplified draft, without push it_) then I will apply it on some big PHP library and run tests. I understand that modify self:: to static:: will change the code behaviour, but the question is if it affects a real code - from a _library_, for instance. In my mind, it will make possible child override more methods with security.

Quote 1: Can we use static:: instead of self:: in all cases?

For instance, in your first example, you are reading the "original value" of a constant (defined at const A::DF = 123) and ignoring the new overriden value (defined at const B::DF = 44), even calling from B. It seems very confuses for me. Imagine that you misused self:: here, instead of use static::. Maybe you uses a lot of time to identify that your calculation is wrong because of that (_it was my original case_).

PHP don't supports final constants, so I could rewrite the code like that to make sure that my original value will be available all the time:

class ParentClass {
    const CONST_COULD_BE_OVERRIDEN = 100;

    private static final function getGravityAcceleration() {
        return 9.789;
    }

    public function calculate(){
        // Note: "static::getGravityAcceleration()" make no sense here.
        echo static::CONST_COULD_BE_OVERRIDEN * self::getGravityAcceleration();
    }
}

class ChildClass extends ParentClass {
    const CONST_COULD_BE_OVERRIDEN = 200;
}

(new ParentClass())->calculate(); // => 978.9
(new ChildClass())->calculate();  // => 1957.8

It will close absolutely the getGravityAcceleration() for child modifications, and remove any doubt about the expected result.

Quote 2: Suggests static:: instead of self:: if method is not-final

It is a good false-positive. We can warn user to use self:: instead of static:: if field (const or property) is private with two quick-fixes: set field to protected or use self instead of static.

PHP don't supports final constants

You can make constant private

What about inspection: self instead of static? Only in places that can be made without BC ;)

So... The idea is suggest the best keyword for each case: self instead of static for private const, for instance, and static instead of self for public const.

Bebo beep, the StaleBot is here. For one year nothing have happened here. It would be great if someone looked into details here within next 21 days when I'll close it.

Was this page helpful?
0 / 5 - 0 ratings