Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calling instance methods statically from within the class

Tags:

php

According to one of the man pages http://www.php.net/manual/en/language.oop5.static.php :

Calling non-static methods statically generates an E_STRICT level warning.

But, this doesn't seem to be the case when the call is made from inside the class:

error_reporting(-1);

class Test {
    private $id;
    function __construct($id) { $this->id = $id; }
    function id() { return $this->id; }

    function __toString() {
        return Test::id()
             . self::id()
             . static::id()
             . static::id()
             . call_user_func('Test::id')
             . call_user_func(array('Test', 'id'));
    }
}
$a = new Test('a');
$b = new Test('b');


echo "$a $b $a"; # aaaaaa bbbbbb aaaaaa
var_dump(error_get_last()); # NULL

Testing with php 5.4

DEMO: http://codepad.viper-7.com/IKp9iX

I believe I've demonstrated:

  • No E_STRICT warning is generated
  • That php magically corrects the static method call to an instance method call(accessing the instance variable id proves this).

edit- I'd like to add that inserting debug_backtrace() into the __toString call yields a call "type" of ->, which means "method call".

Is this a bug, or a documented feature?

like image 734
goat Avatar asked Jun 22 '12 23:06

goat


2 Answers

If you call a non-static function with static syntax within any class (not just the declaring class), the non-static function behaves as if it were called in the context of the current $this object.

That means that I can use methods from other class' inside my class and those methods will assume my class's $this is their class' $this. If they don't check for InstanceOf or get_class() they will behave exactly the same as usual.

When I say as usual I mean that they will assume that your class' $this has all the other methods and properties that their class' $this would have.

This (I think) is called object context binding. In JavaScript you have to use those call() and/or apply() methods to get a function to behave as if it were attached to a certain object. But in PHP it just works by using the static syntax on non-static functions.

I remember this working in C++ as well but i can't recall if it only worked if the methods belonged to inherited classes (possibly overridden methods that you want to access despite them being overridden).

Using this (hidden) feature you can implement the Decorator design pattern by which you add new functionality to an object at run-time. You can also simulate Mixins or Traits (which PHP 5.4 now supports natively) with the added bonus that this implementation is handled at run-time and as such can be done/ undone dynamically as opposed to the language feature implementation which is handled at compile time and cannot be done/ undone dynamically you have to change the code to change the feature.

like image 106
Mihai Stancu Avatar answered Oct 15 '22 11:10

Mihai Stancu


I'd say it's a semi-documented feature:

In non-static contexts, the called class will be the class of the object instance. Since $this-> will try to call private methods from the same scope, using static:: may give different results. Another difference is that static:: can only refer to static properties.

In other words (as I understood), it can be used to implement late static binding: using self::id() and static::id() may give different results if you call them in some class that extends your Test.

like image 2
raina77ow Avatar answered Oct 15 '22 12:10

raina77ow