【问题标题】:PHP Last Object of Method ChainingPHP 方法链的最后一个对象
【发布时间】:2014-04-17 17:01:58
【问题描述】:

在使用方法链的 PHP 中,如何在链中调用最后一个方法之后提供函数调用?

同时使用相同的实例(见下文)。这会扼杀实现析构函数的想法。

最终结果是从定义的链属性(当然)中返回值和私有“insert()”的函数调用,而无需公开调用它,无论顺序如何。

注意,如果我将这些方法一起回显 (__toString),它将检索最终生成的唯一代码,这是转换字符串的正常行为。

以下示例:

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

123 将根据方法中的所有值生成唯一代码并提供操作,例如自动插入数据库或创建文件(在本例中使用)。

如您所见,没有进行字符串设置、强制转换或回显。

【问题讨论】:

  • 链 1 和 2 是什么/在哪里?
  • 你想在三个方法调用之后运行一些东西?在所有颜色都设置好之后?您想要另一种带有回调的方法吗?在 PHP 神奇地发现你想运行代码之后?另外,析构函数是如何在这一切中发挥作用的?
  • @AmalMurali 将代码向下滚动到末尾。
  • @PeeHaa 正确!包含三个方法调用附加的所有数据的最终回调方法。
  • 那么是什么阻止您添加该方法?

标签: php oop methods chaining method-chaining


【解决方案1】:

你可以保留一份需要初始化的东西的列表,以及它们是否 在这种情况下是否如此。然后每次使用时检查列表 初始化方法之一。比如:

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\n";
    }
}

但我个人认为这会更麻烦,而不是值得。更好的海事组织 公开您的 insert 方法并让您的代码用户告诉您何时 初始化完成。所以应该使用的东西是:

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

-更新-

如果无法预测需要调用哪些函数 您确实需要明确说明。我看不出有什么办法。原因 是不是php真的分不出来

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

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

使用允许重载的语言 = 我想这是可能的,但真的 真的很混乱,通常不是一个好主意。

可以移动显式部分,使其不在调用结束时 链,但我不确定这是否会让你更快乐?也会违背 你不想使用另一个实例的愿望。它可能看起来像这样:

class O {
    public function __construct(InitO $ini) {
        // Do stuff
        echo "Whee\n";
    }
}

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));

您当然可以通过使用其他包装方式只使用一个实例 但我现在能想到的唯一方法看起来更丑陋。

【讨论】:

  • 没有公开实现 insert() :-p 让它自动动态调用类内的 insert 方法。
  • 是的,这是我的第一个例子。我只是认为它是多余的,但它有效。
  • 你的 isInit() 当然可以。但是,它需要通过所有三种颜色!如果一个人只想通过 2 个 red() 函数和 1 个 blue() 函数,而没有 green() 函数怎么办?那么布尔匹配就会失败,insert()不会被触发..
  • 那就真的不行了。请注意,您也不能使用析构函数,因为它会在引用实例的所有变量超出范围时运行,而不是在链结束时运行。链的结尾只是句法。它没有说明稍后将调用哪些方法。
【解决方案2】:

我和 PeeHaa 在一起,这毫无意义! :)

在使用最后一条链后(无法展望未来),唯一有机会神奇地发生某些事情的是析构函数/关闭函数或手动强制转换/调用 insert()

【讨论】:

    【解决方案3】:

    您也可以决定在不使用对象的情况下静态实现。

    <?php
    class Object
    {
        private static $data;
    
        public static function set($name) 
        {
            // ... some other code stuff
        }
    
        private static function fc($num) 
        {
            // some wicked code here
        }
    
        public static function green($num) 
        {
            self::$data .= self::fc($num*10);
            return new static;
        }
    
        public static function red($num) 
        {
            self::$data .= self::fc($num*25);
            return new static;
        }
    
        public static function blue($num) {
            self::$data .= self::fc($num*1);
            return new static;
        }
    
        // how to get this baby to fire ?
        public static function insert() 
        {
           // inserting
           file_put_content('test_code.txt', self::$data);
        }
    
    }
    
    //$tss = new object('index_elements');
    
        $Object::set('index_elements')->blue(100)->green(200)->red(100)->insert();       // chain 1
        $Object::set('index_elements')->green(0)->red(100)->blue(0)->insert();           // chain 2
        $Object::set('index_elements')->blue(10)->red(80)->blue(10)->green(0)->insert(); // chain 3
    
    ?>
    

    【讨论】:

      【解决方案4】:

      好的,让我们看一个代码示例

      <?php
      
      // map dummy class
      class map
      {
      // __call magic method
      public function __call($name, $args)
      {
      return $this;
      }
      }
      
      // now we chain
      $map = new map;
      
      // let's find me
      
      $map->start('here')
      ->go('right')
      ->then()
      ->turn('left')
      ->and('get water')
      ->dontEat()
      ->keep('going')
      ->youShouldSeeMe('smiling');
      

      这里我们不知道最后一个方法是什么,我们需要在结束时触发某种操作或事件。

      根据数据结构,我们可以将其称为 LIFO 堆栈。 (后进先出)

      那么我是如何在 PHP 上解决这个问题的呢?

      // 我做了一些回溯

      ...回到__call函数

      function __call($name, $args)
      {
      
      $trace = debug_backtrace()[0];
      $line = $trace['line'];
      $file = $trace['file'];
      $trace = null;
      $getFile = file($file);
      $file = null;
      $getLine = trim($getFile[$line-1]);
      $line = null;
      $getFile = null;
      
      $split = preg_split("/(->)($name)/", $getLine);
      $getLine = null;
      
      if (!preg_match('/[)](->)(\S)/', $split[1]) && preg_match('/[;]$/', $split[1]))
      {
      // last method called.
      var_dump($name); // outputs: youShouldSeeMe
      }
      
      $split = null;
      
      return $this;
      }
      

      而且,一旦我们触底,我们就可以调用任何东西。 *(请注意,我在处理完变量后使用 null,我来自 C 家族,我们自己管理内存)

      希望它对您有所帮助。

      【讨论】:

        猜你喜欢
        • 2013-01-15
        • 2013-05-23
        • 1970-01-01
        • 2015-08-06
        • 2018-10-14
        • 2022-01-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多