在 PHP 5.4.0 之前的版本中,在匿名函数中使用 `$this`。

91
PHP手册说明:在PHP 5.4.0之前的匿名函数中,无法使用$this。可以在匿名函数页面上查看相关信息。但我发现,通过将$this赋值给一个变量,并将该变量传递给函数定义处的use语句,可以使其正常工作。
$CI = $this;
$callback = function () use ($CI) {
    $CI->public_method();
};

这是一个好的实践吗?
在 PHP 5.3 中,有更好的方法来使用匿名函数访问 $this 吗?


1
只是一个小的论坛惯例 - 接受一个答案通常比编辑问题以反映您偏爱的答案更好。主要是为了让回复在永久存在时仍然有意义,当然也是为了给予正确答案应有的荣誉。 - halfer
4
请注意,$CI = $this;$CI =& $this; 并不完全相同。也许对于你的目的来说它们是相同的,但它们并不相同。使用这两个版本尝试 $CI = 'bla'; var_dump($this); 以查看差异。 - Rudie
1
@Rudie 我正在为你的评论添加文档 - steampowered
@steampowered 在网上有一个很好的关于这个的例子/文章,但我找不到了 =)抱歉。如果你看不出区别,就试一下。那时候显而易见。 - Rudie
5个回答

70

如果你试图在外部调用一个受保护或私有的方法,它将会失败,因为使用这种方式相当于从外部调用。在我所知道的5.3版本中没有解决此问题的方法,但是在PHP 5.4中,它将如预期一样开箱即用:

class Hello {

    private $message = "Hello world\n";

    public function createClosure() {
        return function() {
            echo $this->message;
        };
    }

}
$hello = new Hello();
$helloPrinter = $hello->createClosure();
$helloPrinter(); // outputs "Hello world"

更重要的是,您将能够在运行时更改匿名函数(闭包重新绑定)中$this指向的对象:

class Hello {

    private $message = "Hello world\n";

    public function createClosure() {
        return function() {
            echo $this->message;
        };
    }

}

class Bye {

    private $message = "Bye world\n";

}

$hello = new Hello();
$helloPrinter = $hello->createClosure();

$bye = new Bye();
$byePrinter = $helloPrinter->bindTo($bye, $bye);
$byePrinter(); // outputs "Bye world"

匿名函数将拥有一个bindTo()方法,第一个参数可用于指定 $this 指向的对象,第二个参数控制可见级别应该是什么。如果省略第二个参数,则可见性将类似于从“外部”调用,例如只能访问公共属性。还要注意 bindTo 的工作方式,它不会修改原始函数,而是返回一个新函数


1
将您的答案标记为正确,但是为了澄清其他读者:问题中使用的约定将适用于使用引用“$this”的对象的公共方法。 - steampowered
5
非公开方法可以使用反射访问。虽然效率低下且有点不太好,但它确实有效。 - outis

11

在PHP中,不要总是依赖传递对象引用来进行操作,当你给一个引用本身进行赋值时,它的行为和大多数面向对象语言不同,原始指针不会被修改。

你的例子:

$CI = $this;
$callback = function () use ($CI) {
$CI->public_method();
};

应该是:

$CI = $this;
$callback = function () use (&$CI) {
$CI->public_method();
};

请注意引用符 "&" 和 $CI 应该在完全调用它之后再分配,否则您可能会得到不可预测的输出。在 PHP 中访问引用并不总是与访问原始类相同 - 如果这有意义的话。

http://php.net/manual/en/language.references.pass.php


7

这是通常的做法。
顺便说一下,尝试删除&,因为对象本身就是通过引用传递的,所以没有这个也可以正常工作。


1

如果你是通过引用传递参数,那么这种方式看起来很好。如果你使用的是PHP 5,那么在$this之前不需要加上&符号,因为它总是通过引用传递。


2
OP 必须使用 5.3 或更高版本,因为 4.x 不支持匿名函数 :-) - halfer

1

这很好。我认为你也可以这样做:

$CI = $this;

......因为涉及对象的赋值操作总是会复制引用,而不是整个对象。


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