【问题标题】:Why can I not use $this as a lexical variable in PHP 5.5.4?为什么我不能在 PHP 5.5.4 中使用 $this 作为词法变量?
【发布时间】:2013-10-17 15:50:25
【问题描述】:
$ php --version
PHP 5.5.4 (cli) (built: Sep 19 2013 17:10:06) 
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2013 Zend Technologies

以下代码(类似于https://bugs.php.net/bug.php?id=49543 的示例):

class Foo
{
    public function bar()
    {
        return function() use ($this)
        {
            echo "in closure\n";
        };
    }
}

失败:

PHP Fatal error:  Cannot use $this as lexical variable

然而,根据 PHP 文档和 Rasmus Lerdorf 对该错误报告的评论,在 PHP 5.4 中添加了在匿名函数中使用 $this。我做错了什么?

【问题讨论】:

  • 检查以确保您使用的是来自 Web 服务器的相同版本的 PHP。它通常与你在 Bash 中的第一个路径不同。使用phpinfo()
  • 根据3v4l.org/G28oE 中的快速测试,即使在 5.5.5 中也是如此……也许 Rasmus 在这个问题上是错的……?编辑:或者在他说这个的时候可能打算在 5.4 中(懒得查找知道 5.4 到那时是否已经出来了),但他们再次删除了它,因为它导致了额外的问题他们实现它的方式。
  • @Brad 值得一提,但我用 cli 对此进行了测试。

标签: php


【解决方案1】:

因此,如果 $this 不是通过“use”关键字指定的,那么它似乎可以简单地使用。

以下回显“bar”:

class Foo
{
    private $foo = 'bar';

    public function bar()
    {
        return function()
        {
            echo $this->foo;
        };
    }
}

$bar = (new Foo)->bar();

$bar();

这是在 php-internals 邮件列表中报告的,显然是由于 5.3 不支持此功能:

http://marc.info/?l=php-internals&m=132592886711725

【讨论】:

  • 仅供 PHP 7 用户参考,这个答案仍然绝对正确。
  • 这个答案应该在顶部!虽然仍然存在 7
【解决方案2】:

PHP 5.3 中,如果您在类中使用Closure,则Closure 将无法访问$this

PHP 5.4 中,添加了对在Closures 中使用$this 的支持。

【讨论】:

  • 很好的答案,你能提供出处吗?
  • 仅在 5.4 中,这意味着 5.3 不支持 $this 内部附件?谢谢
【解决方案3】:

我不知道你的实际问题的答案(即为什么你不能这样做),但我可以给你一个解决方法:使用$thisuse() 的临时副本:

class Foo
{
    public function bar()
    {
        $that = $this;
        return function() use($that)
        {
            print_r($that);
        };
    }
}

我刚刚测试过,这确实有效。

【讨论】:

  • 将对象分配给变量是通过引用完成的,所以temporary copy of $this实际上是$that is reference of $this。不过话说回来,为什么不能在use语句中使用$this,而可以使用引用赋值的变量呢?
【解决方案4】:

问题是不允许在use() 语句中包含$this

但是,如果您不包含它,那么它会正常工作。

所以问题不在于 use 语句是否存在,而在于$this 是否存在于use 语句中。

这应该可以工作(@see https://3v4l.org/smvPt):

class Foo{
    private $a;
    function getAnon(){
        $b = 1;
        return function() use ($b) { 
            echo $b;
            echo $this->a;
        };
    }
}

这不应该:

class Foo{
    private $a;
    function getAnon(){
        $b = 1;
        return function() use ($this, $b) { 
            echo $b;
            echo $this->a;
        };    
    }
}

我想基本上$this 是隐式捕获的。

【讨论】:

    【解决方案5】:

    你可以用这个:

    class Foo
    {
      public function bar()
      {
        $obj = $this;
        return function() use ($obj)
        {
            //$obj->DoStuff();
            echo "in closure\n";
        };
      }
     }
    

    【讨论】:

      【解决方案6】:

      我知道,这是一个老问题,但也许有人从谷歌找到这个:

      你得到错误的原因是,你不能在同一个闭包中使用已经定义的变量名作为词法变量。

      由于在 PHP 5.5 及更高版本中,您可以在闭包内访问 $this,因此名称为 $this 的变量已经存在。

      这是另一个例子,你会得到同样的错误:

      $item = "Test 1";
      $myFnc = function($item) use ($item) {
          ...
      }
      $myFnc("Test 2");
      

      如您所见,$item 已经用作闭包参数,因此您不能使用它作为词法变量。

      【讨论】:

        【解决方案7】:

        这可能是一个错误,但是将$this 显式绑定到函数是没有意义的,因为它是自动绑定的:

        PHP documentation

        从 PHP 5.4.0 开始,当在类的上下文中声明时,当前 类自动绑定到它,使 $this 在内部可用 函数的作用域。

        因此,在今天的 PHP 版本中抛出了致命错误:

        从 PHP 7.1 开始,这些变量不得包含超全局变量、$this 或与参数同名的变量。

        【讨论】:

          【解决方案8】:

          我使用的是 PHP 5.4.25,实际上我还可以使用 use 关键字在闭包中使用类变量,如下所示:

          class Foo
          {
              private $_privateBar = 'private bar';
              protected $_protectedBar = 'protected bar';
              public $_publicBar = 'public bar';
          
              public function bar()
              {
                  $prefix = 'I am a ';
          
                  return function() use ($prefix) {
                      echo $prefix . $this->_privateBar . "\n";
                      echo $prefix . $this->_protectedBar . "\n";
                      echo $prefix . $this->_publicBar . "\n";
                  };
              }
          }
          
          $foo = new Foo();
          $bar = $foo->bar();
          
          $bar();
          

          输出:

          I am a private bar
          I am a protected bar
          I am a public bar
          

          【讨论】:

          • 问题不在于use 关键字隐式阻止使用$this - 而是为什么use ($prefix, $this)(如果在您的示例中使用)将是不必要/无效的。
          • 克里斯蒂亚诺的回答在我看来就像是要强调您在其中写道的不准确陈述:“因此,如果根本没有指定“使用”关键字,则似乎可以使用此 $this ”。根据克里斯蒂亚诺的代码(我亲自尝试过,它就像一个魅力)你的答案是完全错误的。您应该考虑将此标记为正确答案。
          • 啊,我没有意识到他是在回答我的回答而不是我的问题。事实上,开头的句子可能具有误导性 - 它特定于原始问题,其中 $this 是唯一被传递的变量,function() use () 无效。固定。
          猜你喜欢
          • 2012-01-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多