dsqve08622 2014-04-17 17:01
浏览 49
已采纳

PHP方法链接的最后一个对象

In PHP using method chaining how would one go about supplying a functional call after the last method being called in the chain?

Also while using the same instance (see below). This would kill the idea of implementing a destructor.

The end result is a return value and functional call of private "insert()" from the defined chain properties (of course) without having to call it publicly, no matter of the order.

Note, if I echo (__toString) the methods together it would retrieve the final generated unique code which is normal behavior of casting a string.

Example below:

class object
{
    private $data;
    function __construct($name) {
        // ... some other code stuff
    }

    private function fc($num) {
        // some wicked code here
    }

    public function green($num) {
        $this->data .= fc($num*10);
        return $this;
    }
    public function red($num) {
        $this->data .= fc($num*25);
        return $this;
    }
    public function blue($num) {
        $this->data .= fc($num*1);
        return $this;
    }

    // how to get this baby to fire ?
   private function insert() {
          // inserting
          file_put_content('test_code.txt', $this->data);
   }
}

$tss = new object('index_elements');

$tss->blue(100)->green(200)->red(100);       // chain 1
$tss->green(0)->red(100)->blue(0);           // chain 2
$tss->blue(10)->red(80)->blue(10)->green(0); // chain 3

Chain 1, 2, and 3 would generated an unique code given all the values from the methods and supply an action, e.g. automatically inserting in DB or creating a file (used in this example).

As you can see no string setting or casting or echoing is taking place.

  • 写回答

4条回答 默认 最新

  • dtrovwl75780 2014-04-17 17:18
    关注

    You could keep a list of things that needs to be initialised and whether they have been so in this instance or not. Then check the list each time you use one of the initialisation methods. Something like:

    class O {
        private $init = array
            ( 'red' => false
            , 'green' => false
            , 'blue' => false
            );
    
        private function isInit() {
            $fin = true;
            foreach($this->init as $in) {
                $fin = $fin && $in;
            }
            return $fin;
        }
    
        public function green($n) {
            $this->init['green'] = true;
            if($this->isInit()) {
                $this->insert();
            }
        }
    
        public function red($n) {
            $this->init['red'] = true;
            if($this->isInit()) {
                $this->insert();
            }
        }
    
        public function blue($n) {
            $this->init['blue'] = true;
            if($this->isInit()) {
                $this->insert();
            }
        }
    
        private function insert() {
            echo "whee
    ";
        }
    }
    

    But personally I think this would be more hassle then it's worth. Better imo to expose your insert method and let the user of you code tell when the initialisation is finished. So something that should be used like:

    $o->red(1)->green(2)->blue(0)->insert();
    

    -update-

    If it's the case that it's impossible to predict what functions need to be called you really do need to be explicit about it. I can't see a way around that. The reason is that php really can't tell the difference between

    $o1 = new A();
    $o2 = $o1->stuff();
    

    and

    $o2 = (new A())->stuff();
    

    In a language that allows overloading = I guess it would be possible but really really confusing and generally not a good idea.

    It is possible to move the explicit part so that it's not at the end of the call chain, but I'm not sure if that would make you happier? It would also go against your desire to not use another instance. It could look something like this:

    class O {
        public function __construct(InitO $ini) {
            // Do stuff
            echo "Whee
    ";
        }
    }
    
    class InitO {
        public function red($n) {
            return $this;
        }
        public function green($n) {
            return $this;
        }
        public function blue($n) {
            return $this;
        }
    }
    
    $o = new O((new InitO())->red(10)->red(9)->green(7));
    

    You can of course use just one instance by using some other way of wrapping but the only ways I can think of right now would look a lot uglier.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥30 BC260Y用MQTT向阿里云发布主题消息一直错误
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)