Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

override a static variable

I have two classes (Model and User) but I have a problem so I have tried to explain it in a simple example :

class person
{
    protected static $todo ="nothing";

    public function __construct(){}

    public function get_what_todo()
    {
        echo self::$todo;
    }
}

class student extends person
{
    protected static $todo ="studing";
}

$s = new student();
$s->get_what_todo(); // this will show the word (nothing)
                     //but I want to show the word (studing)

Please give me a solution but without writing any function in the student class I only want to make declarations there :) and thank you :)

like image 210
Khalil Bz Avatar asked Mar 30 '16 12:03

Khalil Bz


4 Answers

The principle is called "late static binding", and was introduced in PHP 5.3.0; with the self keyword to access the property defined in the calling class within the inheritance tree, or static to access the property defined in the child class within that inheritance tree.

class person
{
    protected static $todo ="nothing";

    public function __construct(){}

    public function get_what_todo()
    {
        echo static::$todo;  // change self:: to static::
    }
}

class student extends person
{
    protected static $todo ="studying";
}

class teacher extends person
{
    protected static $todo ="marking";
}

class guest extends person
{
}

$s = new student();
$s->get_what_todo(); // this will show the "studying" from the instantiated child class

$t = new teacher();
$t->get_what_todo(); // this will show the "marking" from the instantiated child class

$g = new guest();
$g->get_what_todo(); // this will show the "nothing" from the parent class,
                     // because $todo is not overriden in the child class
like image 58
Mark Baker Avatar answered Sep 22 '22 21:09

Mark Baker


The reliable way to override a static variable is to do it by redeclaring it. Some people may suggest modifying it in the construct method, but I don't think that's reliable.

It won't reflect the changes until the class is constructed at least once. And of course, in class methods, don't forget to call the static variable using "static::" instead of "self::" when you want to always access the overridden variable.

Here's an example of what I mean: The class Foo is the base class, the class Bar is changing the variable inside its constructor, and the class Baz is overriding the variable in its declaration.

class Foo
{
    public static $a = "base";
}

class Bar extends Foo
{
    function __construct()
    {
        self::$a = "overridden";
    }
}

class Baz extends Foo
{
    public static $a = "overridden";
}

echo 'Foo: ' . Foo::$a . '<br>';
echo 'Bar: ' . Bar::$a . '<br>';
echo 'Baz: ' . Baz::$a . '<br>';
new Bar();
echo 'Bar after instantiation: ' . Bar::$a;

This is the output from phptester.net

Foo: base
Bar: base
Baz: overridden
Bar after instantiation: overridden

As you can see, Bar's way of changing the variable isn't taking effect until after the constructor is called at least once.

EDIT: However, there is another way to edit a variable permanently and reliably: do it after the class declaration. This is especially handy if you only need to modify a variable and not completely override it, like for example an array. It feels a bit dirty, but in theory should work everytime.

class Foo
{
    public static $a = [
        'a' => 'a'
    ];
}

class Bar extends Foo
{
    public static $a;
}
Bar::$a = Foo::$a;
Bar::$a['b'] = 'b';

echo 'Foo: ' . print_r(Foo::$a, true) . '<br>';
echo 'Bar: ' . print_r(Bar::$a, true) . '<br>';

This is the output from phptester.net

Foo: Array ( [a] => a )
Bar: Array ( [a] => a [b] => b ) 

EDIT 2: This last method also gets picked up by ReflectionClass::getStaticPropertyValue in my tests.

like image 38
Guido Belluomo Avatar answered Sep 26 '22 21:09

Guido Belluomo


you can try set variable in construction

class person
{
    protected static $todo = null;

    public function __construct(){
        self::$todo = "nothing";
    }

    public function get_what_todo()
    {
        echo self::$todo;
    }
}

class student extends person
{
    public function __construct() {
       self::$todo = "student";
    }
}

$s = new student();
$s->get_what_todo();
like image 23
Naumov Avatar answered Sep 23 '22 21:09

Naumov


you can try set parent variable in construction

class person
{
    protected static $todo = null;

    public function __construct(){
        self::$todo = "nothing";
    }

    public function get_what_todo()
    {
        echo self::$todo;
    }
}

class student extends person
{
    public function __construct() {
       parent::$todo = "student";
    }
}

$s = new student();
$s->get_what_todo();
like image 28
Aliraza Avatar answered Sep 23 '22 21:09

Aliraza