sanmai sanmai - 25 days ago 19
PHP Question

Detect static function called non-statically

How can one detect that a static function called non-statically?

For example, in this case:

class Foo
{
public static function bar()
{
// How can I tell here that bar() is called on an instance?

//var_dump(debug_backtrace()[0]['type'] == '::');
// at all times the above prints bool(true)
return 1;
}
}

// later in the code
$foo = new Foo();
$foo::bar(); // that's fine

// even later
$foo->bar(); // this should not happen, yet it's here and there


I want to debug and eradicate cases such as on the last line above: someone somewhere wrongly calls a function on an instance, expecting that it would return something related to the instance in subject; instead one gets a somewhat related constant. Subsequently I need to know when this happens. If hell breaks loose or an exception gets thrown is fine with me too.

So far I've found that non-static calls for static functions are internally translated into static calls, hence
debug_backtrace()[0]['type']
tells us nothing (it's
::
in both cases).

Answer

The solution is twofold:

  1. First one needs to disable E_STRICT reporting:

    error_reporting(error_reporting() ^ E_STRICT);
    
  2. Next one should remove static keyword from the function's declaration.

    public /* static */ function bar()
    

Now it is possible to see if a function being called statically or dynamically with help of debug_backtrace function:

class Foo
{
    public function bar()
    {
        $calledStatically = debug_backtrace()[0]['type'] == '::';

        if (!$calledStatically) {
            throw new Exception("Should not happen");
        }

        // ...
    }
}

From the documentation:

type (string): The current call type. If a method call, "->" is returned. If a static method call, "::" is returned. If a function call, nothing is returned.

Quick demo.

Foo::bar(); // normal result returned

$foo = new Foo();
$foo->bar(); // throws exception
Comments