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 adb push异常 adb: error: 1409-byte write failed: Invalid argument
  • ¥15 android报错 brut.common.BrutException: could not exec (exit code = 1)
  • ¥15 nginx反向代理获取ip,java获取真实ip
  • ¥15 eda:门禁系统设计
  • ¥50 如何使用js去调用vscode-js-debugger的方法去调试网页
  • ¥15 376.1电表主站通信协议下发指令全被否认问题
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥15 复杂网络,变滞后传递熵,FDA
  • ¥20 csv格式数据集预处理及模型选择
  • ¥15 部分网页页面无法显示!