Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between static:: and $this::

I know there is a difference between static:: and self:: like in this example ( from https://stackoverflow.com/a/13613718/2342518 )

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

$c = new Two();
$c->test();

Which returns test2 when static::TEST is used and test1 when self::TEST is used. But it also returns test2 when $this::TEST is used.

static::TEST can be used inside a static method, whereas $this::TEST requires an instance before being used (so non-usable in static methods).

But if one cannot use $this:: in static methods, static:: can be used in non-static methods (like in the example).

So, what is the difference between static:: and $this:: in a non static method?


Optional complete test

<?php
abstract class AOne
{
    const TEST = "test1";
    abstract public function test();
}
class OneStatic extends AOne
{
    public function test()
    {
        return static::TEST;
    }
}
class TwoStatic extends OneStatic
{
    const TEST = "test2";
}
class OneSelf extends AOne
{
    public function test()
    {
        return self::TEST;
    }
}
class TwoSelf extends OneSelf
{
    const TEST = "test2";
}
class OneThis extends AOne
{
    public function test()
    {
        return $this::TEST;
    }
}
class TwoThis extends OneThis
{
    const TEST = "test2";
}

$objects = array(
    'one, static::'     => new OneStatic(),
    'two, static::'     => new TwoStatic(),
    'one,   self::'     => new OneSelf(),
    'two,   self::'     => new TwoSelf(),
    'one,  $this::'     => new OneThis(),
    'two,  $this::'     => new TwoThis(),
);

$results = array();
foreach ($objects as $name=>$object)
    $results[$name] = $object->test();

var_dump($results);
?>

Which yields

  • 'one, static::' => 'test1'
  • 'two, static::' => 'test2'
  • 'one, self::' => 'test1'
  • 'two, self::' => 'test1'
  • 'one, $this::' => 'test1'
  • 'two, $this::' => 'test2'

So self refers to the class where the method is defined, but there's no difference between $this:: and static:: in these non static methods.

like image 932
Xenos Avatar asked Jun 29 '14 12:06

Xenos


People also ask

What is difference between static and non static?

Static variables are shared among all instances of a class. Non static variables are specific to that instance of a class. Static variable is like a global variable and is available to all methods. Non static variable is like a local variable and they can be accessed through only instance of a class.

What is static :: in PHP?

The static keyword is used to declare properties and methods of a class as static. Static properties and methods can be used without creating an instance of the class. The static keyword is also used to declare variables in a function which keep their value after the function has ended.

Why this is not used in static?

"this" keyword is only applicable where an instance of an object is created. And in static method no instance is created because static method belongs to class area.

Can static used with this?

No, the "this" keyword cannot be used to refer to the static members of a class. This is because the “this” keyword points to the current object of the class and the static member does not need any object to be called.


2 Answers

There are three cases when you CAN'T use $this:: over static::

1. In static methods

public static function test() {
    return $this::MY_CONST;
}

Output:

Fatal error: Uncaught Error: Using $this when not in object context

2. In none-static methods which get called in none-object context

class A {
    const MY_CONST = 33;
    public function test() {
        return $this::MY_CONST;
    }
}

echo A::test(); // test method here is called without instantiating class A

Output:

Fatal error: Uncaught Error: Using $this when not in object context

3. When using the special ::class keyword

class A {
    public function test() {
        return $this::class;
    }
}

$a = new A;
echo $a->test();

Output:

Fatal error: Dynamic class names are not allowed in compile-time

Note: in all the three cases static:: will work


For the last case PHP Documentation states that:

Note:

The class name resolution using ::class is a compile time transformation. That means at the time the class name string is created no autoloading has happened yet. As a consequence, class names are expanded even if the class does not exist. No error is issued in that case.

So you can't use $this::class because you can't reference to non-existent classes

PHP 8

The behavior in PHP 8 has changed!

For consistency reasons $this::class now provides the same result as get_class($this) and static::class

https://3v4l.org/iB99O

like image 81
Rain Avatar answered Nov 08 '22 23:11

Rain


There really isn't one. The :: functionality has been expanded over time, so that the left hand side doesn't need to be a class literal but may also be an object instance or string variable with a class name. Sometime around the same time late static binding was introduced with the static keyword. As you said, $this can't be used in static methods, so static is the obvious and only choice here for late static binding.

In an object instance however you could use static:: to refer to the late-static bound class, which will be the class of the current object instance. Or you could use $this:: as a side effect of being able to use an object instance as shorthand for <class of this object $var>::. The end result is the same, it's simply functionality which happens to overlap in this particular point. The internal workings are somewhat different, but I can't think of a case where there would ever be any difference.

Just to complete the Venn diagram:

Only static can do this:

public static function foo() {
    static::FOO;
}

Only $var:: can do this:

$obj = new Foo;
$obj::FOO;

Both can do this:

public function foo() {
    static::FOO;
    $this::FOO;
}
like image 44
deceze Avatar answered Nov 09 '22 00:11

deceze