7

I am trying to create a method inside class, that will instantiate class that is currently in. But I would also need that from this method to work correctly in all extended classes. As I have learned from this thread, it's not good to use self keyword for this task. So obvious choice would be using static keyword.

But, I've come across different method that also works.

Example:

class SimpleClass
{
    private $arg;

    public function __construct( $arg ){
        $this->arg = $arg;
    }

    public function getArg(){return $this->arg;}
    public function setArg($arg){$this->arg = $arg;}

    public function staticInstance()
    {
        return new static( $this->arg );
    }

    public function thisInstance()
    {
        return new $this( $this->arg );
    }

    public function selfInstance()
    {
        return new self( $this->arg );
    }
}

class ExtendedClass extends SimpleClass
{
}

$c1 = 'SimpleClass';
$c2 = 'ExtendedClass';

$inst1 = new $c1('simple');
$inst2 = new $c2('extended');

$static_instance_1 = $inst1->staticInstance();
$this_instance_1 = $inst1->thisInstance();
$self_instance_1 = $inst1->selfInstance();

$static_instance_2 = $inst2->staticInstance();
$this_instance_2 = $inst2->thisInstance();
$self_instance_2 = $inst2->selfInstance();

echo "SimpleClass Instances\n";
echo get_class($static_instance_1);
echo get_class($this_instance_1);
echo get_class($self_instance_1);

echo "ExtendedClass Instances\n";
echo get_class($static_instance_2);
echo get_class($this_instance_2);
echo get_class($self_instance_2);

As I can see from this example, both staticInstance and thisInstance produce "correct" results. Or do they?

Can someone explain difference between these two methods and which one is "correct" one.

Community
  • 1
  • 1
AlFra
  • 379
  • 1
  • 6
  • 17
  • 1
    Not sure, but, as long as you use `new` there is no difference. It's getting interesting when using `clone` and storing the instance in itself. – Daniel W. Jul 09 '14 at 12:39
  • My knowledge of static vs self is such that if, from an object instance of an extended class, you were to call a method that it inherited, which, for example, create a `new static ... `, it will create a new instance of the extended class. Had it have used `self`, it will create a new instance of the parent (because the method exists in the parent) – Alex Jul 09 '14 at 13:42
  • Everything about static and self dilemma is explained in link that I referenced in first paragraph of my question. My dilemma is between $this and static :) – AlFra Jul 09 '14 at 14:06

1 Answers1

5

php.net says:

As of PHP 5.3.0, PHP implements a feature called late static bindings which can be used to reference the called class in a context of static inheritance.

More precisely, late static bindings work by storing the class named in the last "non-forwarding call". In case of static method calls, this is the class explicitly named (usually the one on the left of the :: operator); in case of non static method calls, it is the class of the object. A "forwarding call" is a static one that is introduced by self::, parent::, static::, or, if going up in the class hierarchy, forward_static_call(). The function get_called_class() can be used to retrieve a string with the name of the called class and static:: introduces its scope.

This feature was named "late static bindings" with an internal perspective in mind. "Late binding" comes from the fact that static:: will not be resolved using the class where the method is defined but it will rather be computed using runtime information. It was also called a "static binding" as it can be used for (but is not limited to) static method calls.

Limitations of self:

Static references to the current class like self:: or CLASS are resolved using the class in which the function belongs, as in where it was defined:

<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        self::who();
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test();
?>

The above example will output: A

Late Static Bindings' usage:

Late static bindings tries to solve that limitation by introducing a keyword that references the class that was initially called at runtime. Basically, a keyword that would allow you to reference B from test() in the previous example. It was decided not to introduce a new keyword but rather use static that was already reserved.

<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        static::who(); // Here comes Late Static Bindings
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test();
?>

The above example will output: B

$this keyword refers to current object and you cannot use it in static methods. When you say return $this it means that some method returns the same object on which it was invoked.

So the correct way would be using static keyword because if you say return new static() it refers to the class the method is currently in.

Andy J.
  • 344
  • 2
  • 4
  • 14
  • 1
    I like your answer because it resolves another problem that i have with magic constants :D – AlFra Jul 10 '14 at 05:54
  • Is there a way to get class name without redefining function who? (No extra lines of code in class B) – AlFra Jul 11 '14 at 07:17
  • You can also use php reflection API for this purpose. Something like this: `$reflB = new ReflectionClass('B'); echo $reflB->name;` So you'll get the class name – Andy J. Jul 11 '14 at 11:02