在PHP中传递静态方法作为参数

40

在 PHP 中是否可以像这样做:

myFunction( MyClass::staticMethod );

这样,'myFunction'将具有对静态方法的引用并能够调用它。当我尝试时,我会得到一个"未定义的类常量"(PHP 5.3)错误。所以我猜它不是直接可能的,但是否有一种类似的方法可以实现?到目前为止,我最接近的方法是将“函数”作为字符串传递,并使用call_user_func()。

8个回答

37

用 'php方式' 实现这个功能,是使用与 is_callablecall_user_func 相同的语法。这意味着你的方法对于以下情况都是“中立”的:

  • 一个标准函数名
  • 一个静态类方法
  • 一个实例方法
  • 一个闭包

对于静态方法,这意味着您应该将其作为参数传递:

myFunction( [ 'MyClass', 'staticMethod'] );

或者如果您还没有运行 PHP 5.4:

myFunction( array( 'MyClass', 'staticMethod') );

1
因为call_user_func(function($foo) { echo $foo;}, 'foo')call_user_func([ 'MyClass', 'staticMethod'], 'foo');一样有效,所以它帮了很大的忙。 - gogaz

11

既然您已经提到使用了call_user_func(),并且不想使用该函数或通过将静态函数作为字符串传递的方式来解决问题,这里提供了一种替代方法:使用匿名函数作为静态函数的包装器。

function myFunction( $method ) {
    $method();
}

myFunction( function() { return MyClass::staticMethod(); } );

我不建议这样做,因为我认为call_user_func()方法更加简洁。


9

如果您想避免字符串,可以使用以下语法:

myFunction( function(){ return MyClass::staticMethod(); } );

这段话有些冗长,但它有一个好处,就是可以进行静态分析。换句话说,IDE可以轻松指出静态函数名称中的错误。


MyClass::staticMethod() 不会执行该方法吗? - DanMan
3
@DanMan,一旦执行包装函数,它就会生效。 - Tom

6
让我尝试举一个详细的例子...
您将会这样调用:
myFunction('Namespace\\MyClass', 'staticMethod');

或者这样(如果您有要传递的参数):
myFunction('Namespace\\MyClass', 'staticMethod', array($arg1, $arg2, $arg3));

并且你的函数来接收这个调用:

public static function myFunction($class, $method, $args = array())
{
    if (is_callable($class, $method)) {
        return call_user_func_array(array($class, $method), $args);
    }
    else {
        throw new Exception('Undefined method - ' . $class . '::' . $method);
    }
}

类似的技术在php中常用于装饰器模式


4

针对这个问题:

在 PHP 中能否做到像这样的操作:

myFunction( MyClass::staticMethod );

答案是可以的。你可以让 staticMethod() 返回一个匿名函数,如下所示:

private static function staticMethod()
{
    return function($anyParameters)
    {
        //do something here what staticMethod() was supposed to do
        // ...
        // ...
        //return something what staticMethod() was supposed to return;
    };
}

你可以随后编写


myFunction(MyClass::staticMethod());

但请注意,()是需要用来调用staticMethod()的。这是因为它现在返回了一个匿名函数,该函数包装了最初要执行的静态方法的工作。

当将staticMethod()作为参数传递给另一个函数时,这种方法完全可以正常工作。如果您希望直接调用staticMethod()进行处理,则必须编写以下代码:

MyClass::staticMethod()($doPassInParameters);

请注意,与不需要将其包装在匿名函数中时相比,这可能需要一个额外的冗余步骤来检索函数指针。我只是将其用作参数传递,因此不确定额外步骤的性能惩罚。也许可以忽略不计...

2
这是因为传递常量和函数之间的区别。在没有括号的情况下传递参数名称表示常量(MyClass::staticMethod),而带有括号则表示静态函数(MyClass::staticMethod())。

1

这将在输出中显示第一次调用6和第二次调用9。

$staticmethod1 = function ($max)
{
    return $max*2;
};

$staticmethod2 = function ($max)
{
    return $max*$max;
};

function myfunction($x){
    echo $x(3);
}

myfunction($staticmethod1);
myfunction($staticmethod2);

1
从 PHP 7.4 开始,这非常方便且适合 IDE:
myFunction(fn() => MyClass::staticMethod());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接