如何在没有闭包的情况下使用参数定义回调并在PHP中使用?

时间:2015-08-19 10:47:40

标签: php lambda closures anonymous-function

在PHP中,为了定义回调,可以使用闭包,传递静态参数的工具是use指令。

class MyClass {
    public function foo($x) {
        echo $x;
    }
    public function bar() {
        $x = '123';
        $callback = function () use ($x) {
            $this->foo($x);
        };
        $callback();
    }
}

$myClass = new MyClass();
$myClass->bar();

是否可能/如何避免使用匿名函数并用方法替换它?

class MyClass {
    public function foo($x) {
        echo $x;
    }
    public function baz() {
        $x = '567';
        // There is no function with the name create_user_func.
        // Just to show, what I'm looking for.
        $callback = create_callback([$this, 'foo'], $params = [$x]);
        $callback();
    }
}

$myClass = new MyClass();
$myClass->baz();

修改

一些额外的/背景信息(要明确,我想要实现的目标和原因 - 以及避免误解):

在我的具体情况中,我需要将回调传递给框架的方法。这意味着:我不能/可能不会影响它被调用的方式。

该方法只接受回调本身,没有回调参数。这意味着,回调必须“知道”/提供它所需的静态参数(及其值)。

确切地说,use指令解决了什么。但是我的方法中有多个回调定义,方法也很长。所以我想将回调的逻辑移到单独的方法中。

3 个答案:

答案 0 :(得分:1)

  

但是我的方法中有多个回调定义,方法越来越长。所以我想将回调的逻辑移到单独的方法中。

这是魔术方法__invoke()

的完美示例

对于您需要的每个回调,将其使用的功能和属性提取到新类中。将代码放入新类的__invoke()方法中,将其所需的所有属性初始化为__construct(),然后就可以开始了。

代码:

class MyClass {
    public function bar() {
        $x = '123';
        // Create the callback, pass the values it needs to initialize
        $callback = new ActionFoo($x);
        // Call the callback without arguments
        $callback();
    }
}

class ActionFoo {
    private $x;
    public function __construct($x) {
        $this->x = $x;
    }
    public function __invoke() {
        echo($this->x);
    }
}

$myClass = new MyClass();
$myClass->bar();

答案 1 :(得分:1)

我认为您可以尝试模仿Javascript的bind方法,这是公平的。 PHP中的问题是函数不是一等公民或对象,因此->bind($x)之类的东西是不可能的。也无法传递callable的其他参数。因此,您将 将其包含在某些内容中。

更可重用的方法是编写适当的类:

class CallbackWrapper {
    protected $callable,
              $args;

    public function __construct(callable $callable, array $args) {
        $this->callable = $callable;
        $this->args     = $args;
    }

    public function __invoke() {
        call_user_func_array($this->callable, $this->args);
    }
}

giveMeACallback(new CallbackWrapper([$this, 'foo'], [$x]));

或者你只是简化了匿名函数的构建:

function make_callback(callable $callable, array $args) {
    return function () use ($callable, $args) {
        return call_user_func_array($callable, $args);
    };
}

giveMeACallback(make_callback([$this, 'foo'], [$x]));

答案 2 :(得分:0)

有很多方法可以实现这一目标。

  1. 使用辅助功能。
  2. 代码:

    class MyClass {
        private $x;
    
        public function foo() {
            echo $this->x;
        }
        public function bar() {
            $this->x = '123';
            anon($this);
        }
    }
    
    $myClass = new MyClass();
    $myClass->bar();
    
    function anon($obj) {
        $obj->foo();
    }
    
    1. 使用 call_user_func
    2. 代码:

      class MyClass {
          private $x;
      
          public function foo() {
              echo $this->x;
          }
          public function bar() {
              $this->x = '123';
              call_user_func([$this, 'foo']);
          }
      }
      
      $myClass = new MyClass();
      $myClass->bar();
      
      1. 如果由于某种原因您不想使用成员变量,可以使用 call_user_func_array传递参数。
      2. 代码:

        class MyClass {
            private $x;
        
            public function foo($x) {
                echo $x;
            }
            public function bar() {
                $x = '123';
                call_user_func_array([$this, 'foo'], [$x]);
            }
        }
        
        $myClass = new MyClass();
        $myClass->bar();