Ссылка на статический метод в PHP? - PullRequest
18 голосов
/ 10 октября 2008

В PHP я могу без проблем использовать обычную функцию в качестве переменной, но я не понял, как использовать статический метод. Я просто пропускаю правильный синтаксис или это невозможно?

(РЕДАКТИРОВАТЬ: первый предложенный ответ не работает. Я расширил мой пример, чтобы показать возвращенные ошибки.)

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();

(я использую PHP v5.2.6 - ответ также меняется в зависимости от версии?)

Ответы [ 8 ]

28 голосов
/ 10 октября 2008

PHP обрабатывает обратные вызовы как строки, а не как указатели на функции. Причина, по которой ваш первый тест работает, заключается в том, что интерпретатор PHP принимает foo1 в виде строки. Если у вас включена ошибка уровня E_NOTICE, вы должны увидеть доказательство этого.

"Использование неопределенной константы foo1 - предполагается, что 'foo1'"

К сожалению, вы не можете вызывать статические методы таким образом. Область (класс) имеет значение, поэтому вам нужно использовать call_user_func.

<?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();
9 голосов
/ 10 октября 2008

В php 5.2 вы можете использовать переменную в качестве имени метода при статическом вызове, но чтобы использовать переменную в качестве имени класса, вам придется использовать обратные вызовы, как описано в BaileyP.

Однако, начиная с php 5.3, вы можете использовать переменную в качестве имени класса в статическом вызове. Так:

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();
?>
4 голосов
/ 20 июня 2012

Вы можете использовать полное имя статического метода, включая пространство имен.

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

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

Массив имен array('YourClass', 'staticMethod') равен ему. Но я думаю, что строка может быть более понятной для чтения.

1 голос
/ 20 августа 2010

В PHP 5.3.0 вы также можете сделать следующее:

<?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);

?>
0 голосов
/ 18 декабря 2013

Исходя из фона javascript и будучи испорченным им, я просто закодировал это:

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());
    };
}

Чтобы использовать это:

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

Это функция, которая возвращает функцию, которая вызывает функцию, которую вы хотели вызвать. Звучит причудливо, но, как вы можете видеть на практике, это кусок пирога.

Работает с пространствами имен, и возвращаемая функция должна работать так же, как статический метод - параметры работают одинаково.

0 голосов
/ 08 января 2013

В дополнение к тому, что было сказано, вы также можете использовать возможности отражения PHP:

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');
    }

}
0 голосов
/ 11 октября 2008

Мне кажется, это работает:

<?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();

?>
0 голосов
/ 10 октября 2008

"Член или метод, объявленный с использованием static, не могут быть доступны с помощью переменной, которая является экземпляром объекта и не может быть переопределена в расширяющем классе"

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...