将闭包定义为类中的方法

Cha*_*les 14 php closures

我正在尝试使用php5.3和关闭.

我在这里看到(清单7.对象内部的闭包:http://www.ibm.com/developerworks/opensource/library/os-php-5.3new2/index.html),可以在回调函数中使用$ this ,但事实并非如此.所以我尝试将$ this作为使用变量:

$self = $this;
$foo = function() use($self) { //do something with $self }
Run Code Online (Sandbox Code Playgroud)

所以要使用相同的例子:

class Dog
{
private $_name;
protected $_color;

public function __construct($name, $color)
{
     $this->_name = $name;
     $this->_color = $color;
}
public function greet($greeting)
{
     $self = $this;
     return function() use ($greeting, $self) {
         echo "$greeting, I am a {$self->_color} dog named {$self->_name}.";
     };
}
}

$dog = new Dog("Rover","red");
$dog->greet("Hello");

Output:
Hello, I am a red dog named Rover.
Run Code Online (Sandbox Code Playgroud)

首先这个例子不打印字符串但返回函数,但这不是我的问题.

其次我无法访问private或protected,因为回调函数是一个全局函数,而不是来自Dog对象的上下文.不是我的问题.它与以下相同:

function greet($greeting, $object) {
    echo "$greeting, I am a {$self->_color} dog named {$self->_name}.";
}
Run Code Online (Sandbox Code Playgroud)

而且我要 :

public function greet($greeting) {
    echo "$greeting, I am a {$self->_color} dog named {$self->_name}.";
}
Run Code Online (Sandbox Code Playgroud)

哪个来自Dog而不是全球.

irc*_*ell 9

好吧,你不能使用$ this的全部原因是因为闭包是后台的一个对象(Closure类).

有两种方法可以解决这个问题.首先,添加__invoke方法(如果调用$ obj(),则调用什么)

class Dog {

    public function __invoke($method) {
        $args = func_get_args();
        array_shift($args); //get rid of the method name
        if (is_callable(array($this, $method))) {
            return call_user_func_array(array($this, $method), $args);
        } else {
            throw new BadMethodCallException('Unknown method: '.$method);
        }
    }

    public function greet($greeting) {
        $self = $this;
        return function() use ($greeting, $self) {
            $self('do_greet', $greeting);
        };
    }

    protected function do_greet($greeting) {
        echo "$greeting, I am a {$this->_color} dog named {$this->_name}.";
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您希望在修改主机对象时不更改闭包,则只需将返回函数更改为:

public function greet($greeting) {
    $self = (clone) $this;
    return function() use ($greeting, $self) {
        $self('do_greet', $greeting);
    };
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是提供一个通用的getter:

class Dog {

    public function __get($name) {
        return isset($this->$name) ? $this->$name : null;
    }

}
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅:http://www.php.net/manual/en/language.oop5.magic.php


Fel*_*ing 3

那么,您无法访问对象的私有字段和受保护字段是有道理的。通过显式传递$self给您的函数,它会被视为普通对象。
您应该创建 getter 来访问这些值,即:

class Dog
{
    private $_name;
    protected $_color;

    public function __construct($name, $color)
    {
         $this->_name = $name;
        $this->_color = $color;
    }
    public function getName() {
        return $this->_name;
    }
    public function getColor() {
        return $this->_color;
    }
    public function greet($greeting)
    {
         $self = $this;
         return function() use ($greeting, $self) {
             echo "$greeting, I am a {$self->getColor()} dog named {$self->getName()}.";
         };
    }
}
Run Code Online (Sandbox Code Playgroud)

无论如何,出于封装的考虑,您应该创建 getter(和 setter) 。


另请注意:您链接到的文章是在 PHP 5.3 最终版本发布之前发布的。也许这个隐式对象传递被删除了。