What is the difference between self::$bar and static::$bar in PHP?
PhpOopPhp 5.3Php Problem Overview
What is the difference between using self
and static
in the example below?
class Foo
{
protected static $bar = 1234;
public static function instance()
{
echo self::$bar;
echo "\n";
echo static::$bar;
}
}
Foo::instance();
###produces
1234
1234
Php Solutions
Solution 1 - Php
When you use self
to refer to a class member, you're referring to the class within which you use the keyword. In this case, your Foo
class defines a protected static property called $bar
. When you use self
in the Foo
class to refer to the property, you're referencing the same class.
Therefore if you tried to use self::$bar
elsewhere in your Foo
class but you had a Bar
class with a different value for the property, it would use Foo::$bar
instead of Bar::$bar
, which may not be what you intend:
class Foo
{
protected static $bar = 1234;
}
class Bar extends Foo
{
protected static $bar = 4321;
}
When you call a method via static
, you're invoking a feature called late static bindings (introduced in PHP 5.3).
In the above scenario, using self
will result in Foo::$bar
(1234).
And using static
will result in Bar::$bar
(4321) because with static
, the interpreter takes into account the redeclaration within the Bar
class during runtime.
// self
var_dump(Foo::$bar);
// (int) 1234
// static
var_dump(Bar::$bar);
// (int) 4321
You typically use late static bindings for methods or even the class itself, rather than properties, as you don't often redeclare properties in subclasses; an example of using the static
keyword for invoking a late-bound constructor can be found in this related question: https://stackoverflow.com/questions/5197300/new-self-vs-new-static
However, that doesn't preclude using static
with properties as well.
Solution 2 - Php
I have small example showing difference between self
and static
. Using static::
performs Late Static Binding and thus it binds the variable value from child class.
class A { // Base Class
protected static $name = 'ClassA';
public static function getSelfName() {
return self::$name;
}
public static function getStaticName() {
return static::$name;
}
}
class B extends A {
protected static $name = 'ClassB';
}
echo B::getSelfName(); // ClassA
echo B::getStaticName(); // ClassB
Solution 3 - Php
With self
call:
class Phone
{
protected static $number = 123;
public function getNumber()
{
return self::$number;
}
}
class Fax extends Phone
{
protected static $number = 234;
}
// Displays: "123"
echo (new Fax)->getNumber();
You can see above, even though we have overridden the $number
with our Fax
class, getNumber()
still returns 123
.
This because we have asked PHP to give us the variable where it was defined in -- which will return Phone
s variable instead.
If we swap the self
call with static
, we will get Fax
s overridden value instead:
With static
call:
class Phone
{
protected static $number = 123;
public function getNumber()
{
return static::$number;
}
}
class Fax extends Phone
{
protected static $number = 234;
}
// Displays: "234"
echo (new Fax)->getVar();
Solution 4 - Php
As mentioned one of the main differences is that static
allows for late static bindings. One of the most useful scenarios that I found was for creating Base classes for Singleton Classes:
class A { // Base Class
protected static $name = '';
protected static function getName() {
return static::$name;
}
}
class B extends A {
protected static $name = 'MyCustomNameB';
}
class C extends A {
protected static $name = 'MyCustomNameC';
}
echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC
Using return static::$name
in the Base class will return what was statically attached when it was extended. If you were to use return self::$name
then B::getName()
would return an empty string as that is what is declared in the Base class.
Solution 5 - Php
Maybe this self-explained code helps you:
> class Foo
> {
> protected static $bar = 'parent value';
>
> public static function test()
> {
> var_dump('I am your father');
> var_dump('self:: here means '.self::$bar);
> var_dump('static:: here means '.static::$bar);
> }
> }
>
> class Bar extends Foo
> {
> protected static $bar = 'child value';
>
> public static function test()
> {
> parent::Test();
>
> var_dump('I am the child');
> var_dump('self:: here means '.self::$bar);
> var_dump('static:: here means '.static::$bar);
> }
> }
>
> Bar::test();
> Foo::test();
This produces the following output (I have added Line Breaks for clarity):
'I am your father' (length=16)
'self:: here means parent value' (length=30)
'static:: here means child value' (length=31)
'I am the child' (length=14)
'self:: here means child value' (length=29)
'static:: here means child value' (length=31)
'I am your father' (length=16)
'self:: here means parent value' (length=30)
'static:: here means parent value' (length=32)