23

In PHP, I am able to use a normal function as a variable without problem, but I haven't figured out how to use a static method. Am I just missing the right syntax, or is this not possible?

(EDIT: the first suggested answer does not seem to work. I've extended my example to show the errors returned.)

function foo1($a,$b) { return $a/$b; }

class Bar
{
    static function foo2($a,$b) { return $a/$b; }

    public function UseReferences()
    {
        // WORKS FINE:
        $fn = foo1;
        print $fn(1,1);

        // WORKS FINE:
        print self::foo2(2,1);
        print Bar::foo2(3,1);

        // DOES NOT WORK ... error: Undefined class constant 'foo2'
        //$fn = self::foo2;
        //print $fn(4,1);

        // DOES NOT WORK ... error: Call to undefined function self::foo2()
        //$fn = 'self::foo2';
        //print $fn(5,1);

        // DOES NOT WORK ... error: Call to undefined function Bar::foo2()        
        //$fn = 'Bar::foo2';
        //print $fn(5,1);

     }
}

$x = new Bar();
$x->UseReferences();

(I am using PHP v5.2.6 -- does the answer change depending on version too?)

8 Answers 8

30

PHP handles callbacks as strings, not function pointers. The reason your first test works is because the PHP interpreter assumes foo1 as a string. If you have E_NOTICE level error enabled, you should see proof of that.

"Use of undefined constant foo1 - assumed 'foo1'"

You can't call static methods this way, unfortunately. The scope (class) is relevant so you need to use call_user_func instead.

<?php

function foo1($a,$b) { return $a/$b; }

class Bar
{
    public static function foo2($a,$b) { return $a/$b; }

    public function UseReferences()
    {
        $fn = 'foo1';
        echo $fn(6,3);

        $fn = array( 'self', 'foo2' );
        print call_user_func( $fn, 6, 2 );
     }
}

$b = new Bar;
$b->UseReferences();
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, call_user_func does the trick. I note that if the function is passed to a method in the other class then, not unnaturally, it needs to be scoped with 'Bar' instead of 'self'.
"PHP handles callbacks as strings, not function pointers." This is exactly what I was looking for
10

In php 5.2, you can use a variable as the method name in a static call, but to use a variable as the class name, you'll have to use callbacks as described by BaileyP.

However, from php 5.3, you can use a variable as the class name in a static call. So:

class Bar
{
    public static function foo2($a,$b) { return $a/$b; }

    public function UseReferences()
    {
        $method = 'foo2';
        print Bar::$method(6,2); // works in php 5.2.6

        $class = 'Bar';
        print $class::$method(6,2); // works in php 5.3
     }
}

$b = new Bar;
$b->UseReferences();
?>

Comments

7

You could use the full name of static method, including the namespace.

<?php
    function foo($method)
    {
        return $method('argument');
    }

    foo('YourClass::staticMethod');
    foo('Namespace\YourClass::staticMethod');

The name array array('YourClass', 'staticMethod') is equal to it. But I think the string may be more clear for reading.

1 Comment

... Strange, it can't resolve it based on the "use" specification. I needed to pass a static method from a controller on the query_builder of a symfony type class entity type.
1

In PHP 5.3.0, you could also do the following:

<?php

class Foo {
    static function Bar($a, $b) {
        if ($a == $b)
            return 0;

        return ($a < $b) ? -1 : 1;
    }
    function RBar($a, $b) {
        if ($a == $b)
            return 0;

        return ($a < $b) ? 1 : -1;
    }
}

$vals = array(3,2,6,4,1);
$cmpFunc = array('Foo', 'Bar');
usort($vals, $cmpFunc);

// This would also work:
$fooInstance = new Foo();
$cmpFunc = array('fooInstance', 'RBar');
// Or
// $cmpFunc = array('fooInstance', 'Bar');
usort($vals, $cmpFunc);

?>

Comments

1

Coming from a javascript background and being spoiled by it, I just coded this:

function staticFunctionReference($name)
{
    return function() use ($name)
    {
        $className = strstr($name, '::', true);
        if (class_exists(__NAMESPACE__."\\$className")) $name = __NAMESPACE__."\\$name";
        return call_user_func_array($name, func_get_args());
    };
}

To use it:

$foo = staticFunctionReference('Foo::bar');
$foo('some', 'parameters');

It's a function that returns a function that calls the function you wanted to call. Sounds fancy but as you can see in practice it's piece of cake.

Works with namespaces and the returned function should work just like the static method - parameters work the same.

Comments

0

This seems to work for me:

<?php

class Foo{
    static function Calc($x,$y){
        return $x + $y;
    }

    public function Test(){
        $z = self::Calc(3,4);

        echo("z = ".$z);
    }
}

$foo = new Foo();
$foo->Test();

?>

2 Comments

You are just calling Calc(), not storing it in a variable first. Assigning functions to variables and passing them around is useful for writing general purpose algorithms, for example a sort function that accepts different comparison functions for ordering.
Note that if you expect any inherited class to overwrite the Calc() and you want to call the overridden method from Test() instead of verbatim function in class Foo, then you have to use syntax static::Calc(3,4) instead of self::.... The keyword self is a compile time reference to the class that contains the code, the keyword static refers to the current class (which may or may not be the inherited class).
0

In addition to what was said you can also use PHP's reflection capabilities:

class Bar {

    public static function foo($foo, $bar) {
        return $foo . ' ' . $bar;
    }


    public function useReferences () {
        $method = new ReflectionMethod($this, 'foo');
        // Note NULL as the first argument for a static call
        $result = $method->invoke(NULL, '123', 'xyz');
    }

}

Comments

-3

"A member or method declared with static can not be accessed with a variable that is an instance of the object and cannot be re-defined in an extending class"

(http://theserverpages.com/php/manual/en/language.oop5.static.php)

1 Comment

This means that you can't invoke the static method using "$this->", it doesn't mean that you can't pass the static method around in a (effectively function-valued) variable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.