define a closure as method from class

后端 未结 4 402
Happy的楠姐
Happy的楠姐 2020-12-18 21:34

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/in

相关标签:
4条回答
  • 2020-12-18 21:53

    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.

    0 讨论(0)
  • 2020-12-18 21:55

    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.

    0 讨论(0)
  • 2020-12-18 22:01

    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

    0 讨论(0)
  • 2020-12-18 22:01

    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, ' &$');
                       $str_params.='\''.$v.'\'=>&$'.$v.', ';
                      }
              return "return function({$args}) use ({$uses}) {{$fun}(array({$str_params}));};";
             }
    ?>
    

    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)
                                       {//...
                                       }
                                      );
             }
    ?>
    
    0 讨论(0)
提交回复
热议问题