在PHP 5.4.0之前的匿名函数中使用$ this


86

PHP手册指出

$this在PHP 5.4.0之前无法从匿名函数使用

匿名功能页面上。但是我发现我可以通过分配$this给变量并将变量传递给use函数定义的语句来使其工作。

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

这是一个好习惯吗?
有没有更好的方法来$this使用PHP 5.3访问匿名函数内部?


1
只是一个次要的论坛惯例-接受答案通常比编辑问题以反映您的首选答案要好。主要是这样,以便使响应始终永久有效,当然也应归功于正确答案。
Halfer 2011年

4
要注意的是$CI = $this;,并$CI =& $this; 没有实际上是相同的。也许出于您的目的,但它们并不相同。尝试$CI = 'bla'; var_dump($this);使用两个版本,以查看它们之间的区别。
鲁迪2011年

1
@Rudie我正在添加文档以供您评论
动力十足的2011年

@steampowered网上有个很好的例子/文章,但是我找不到它=)对不起。如果看不出区别,请尝试一下。那很明显。
鲁迪

Answers:


67

当您尝试在其上调用受保护的方法或私有方法时,它将失败,因为以这种方式使用它就等于从外部调用。据我所知,在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
蒸汽动力

5
可以使用反射来访问非公共方法。效率低下,有点邪恶,但它可以工作。
outis 2012年

7

不要总是依靠PHP来通过引用传递对象,当您自己分配引用时,其行为与大多数修改原始指针的OO语言不同。

你的例子:

$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



1

如果您通过引用传递是正确的方法,那似乎还不错。如果您使用的是PHP 5,则&以前不需要该符号,$this因为无论如何它始终会通过引用传递。


2
OP必须使用5.3或更高版本,因为4.x不支持匿名功能:-)
Halfer 2011年

1

这可以。我应该认为您也可以这样做:

$CI = $this;

...因为涉及对象的分配将始终复制引用,而不是整个对象。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.