将闭包定义为类中的方法

发布于 2024-09-02 13:26:21 字数 1347 浏览 3 评论 0原文

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

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

$self = $this;
$foo = function() use($self) { //do something with $self }

所以使用相同的示例:

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.

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

其次,我无法访问 private 或 protected,因为回调函数是全局函数,而不是在 Dog 对象的上下文中。那不是我的问题。 相同,

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

它与 : And I Want :

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

它来自 Dog 而不是全局的。

i'm trying to play with php5.3 and closure.

I see here (Listing 7. Closure inside an object : http://www.ibm.com/developerworks/opensource/library/os-php-5.3new2/index.html) that it's possible to use $this in the callback function, but it's not. So I try to give $this as use variable :

$self = $this;
$foo = function() use($self) { //do something with $self }

So to use the same example :

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.

First of all this example does not print the string but return the function, but that's not my problem.

Secondly I can't access to private or protected, because the callback function is a global function and not in the context from the Dog object. Tha't my problem. It's the same as :

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

And I want :

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

Which is from Dog and not global.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

乙白 2024-09-09 13:26:21

好吧,你不能使用 $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}.";
    }
}

如果您希望修改宿主对象时闭包不发生更改,则可以将返回函数更改为类似以下内容:

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

另一个选项,是提供通用的 getter:

class Dog {

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

}

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

Well, the whole reason that you can't use $this, is because the closure is an object in the background (the Closure class).

There are two ways around this. First, is add the __invoke method (What's called if you call $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}.";
    }
}

If you want the closure to not change if you modify the host object, you can just change the return function to something like:

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

The other option, is to provide a generic getter:

class Dog {

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

}

For more information, see: http://www.php.net/manual/en/language.oop5.magic.php

北陌 2024-09-09 13:26:21

从 PHP 5.4.0 Alpha1 开始,您可以从对象实例的上下文中访问 $this

<?php
class Dog
{
  private $_name;
  protected $_color;

  public function __construct($name, $color)
  {
    $this->_name = $name;
    $this->_color = $color;
  }

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

    $func();
  }
}

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

您也可以这样做:

$dog = new Dog("Rover", "red");
$getname = Closure::bind($dog, function() { return $this->_name; });
echo $getname(); // Rover

如您所见,很容易弄乱私有数据。所以要小心。

As of PHP 5.4.0 Alpha1, you can access $this from within the context of an object instance:

<?php
class Dog
{
  private $_name;
  protected $_color;

  public function __construct($name, $color)
  {
    $this->_name = $name;
    $this->_color = $color;
  }

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

    $func();
  }
}

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

You can also do this:

$dog = new Dog("Rover", "red");
$getname = Closure::bind($dog, function() { return $this->_name; });
echo $getname(); // Rover

As you can see, it's possible to easily mess with private data... so be careful.

月竹挽风 2024-09-09 13:26:21

那么,您无法访问对象的私有字段和受保护字段是有道理的。通过显式地将 $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()}.";
         };
    }
}

无论如何,您都应该创建 getter (和 setter),对于 封装


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

Well it makes sense that you cannot access private and protected fields of an object. And by explicitly passing $self to your function, it is treated just as a normal object.
You should create getters in order to access these values , i.e. :

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()}.";
         };
    }
}

You should create getter (and setters) anyway, for matter of encapsulation.


Another note: The article you link to was published before the final version of PHP 5.3 was released. Maybe this implicit object passing was removed.

醉南桥 2024-09-09 13:26:21

我在工作中使用这个 create_closure() 将回调分成类:

<?php
function create_closure($fun, $args, $uses)
         {$params=explode(',', trim($args.','.$uses, ','));
          $str_params='';
          foreach ($params as $v)
                  {$v=trim($v, ' &

示例:

<?php
$loop->addPeriodicTimer(1, eval(create_closure('pop_message', '$timer', '$cache_key, $n, &$response, &$redis_client')));

function pop_message($params)
         {extract($params, EXTR_REFS);
          $redis_client->ZRANGE($cache_key, 0, $n)
                            ->then(//normal
                                   function($data) use ($cache_key, $n, &$timer, &$response, &$redis_client)
                                   {//...
                                   },
                                   //exception
                                   function ($e) use (&$timer, &$response, &$redis_client)
                                   {//...
                                   }
                                  );
         }
?>
); $str_params.='\''.$v.'\'=>&

示例:


.$v.', ';
                  }
          return "return function({$args}) use ({$uses}) {{$fun}(array({$str_params}));};";
         }
?>

示例:

I use this create_closure() in my work to seperate callbacks into Classes:

<?php
function create_closure($fun, $args, $uses)
         {$params=explode(',', trim($args.','.$uses, ','));
          $str_params='';
          foreach ($params as $v)
                  {$v=trim($v, ' &

example:

<?php
$loop->addPeriodicTimer(1, eval(create_closure('pop_message', '$timer', '$cache_key, $n, &$response, &$redis_client')));

function pop_message($params)
         {extract($params, EXTR_REFS);
          $redis_client->ZRANGE($cache_key, 0, $n)
                            ->then(//normal
                                   function($data) use ($cache_key, $n, &$timer, &$response, &$redis_client)
                                   {//...
                                   },
                                   //exception
                                   function ($e) use (&$timer, &$response, &$redis_client)
                                   {//...
                                   }
                                  );
         }
?>
); $str_params.='\''.$v.'\'=>&

example:


.$v.', ';
                  }
          return "return function({$args}) use ({$uses}) {{$fun}(array({$str_params}));};";
         }
?>

example:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文