简体   繁体   English

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

[英]PHP Last Object of Method Chaining

In PHP using method chaining how would one go about supplying a functional call after the last method being called in the chain? 在使用方法链的PHP中,在链中最后一个方法被调用之后,如何进行功能调用呢?

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. 最终结果是从定义的链属性(当然)返回私有私有“ insert()”的返回值和函数调用,而不必公开调用它,而不管顺序如何。

Note, if I echo (__toString) the methods together it would retrieve the final generated unique code which is normal behavior of casting a string. 注意,如果我将(__toString)方法一起回显,它将检索最终生成的唯一代码,这是强制转换字符串的正常行为。

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, eg automatically inserting in DB or creating a file (used in this example). 1,23将来自给定的方法中的所有值和供给的动作,例如,在DB自动插入或创建文件(在本实施例中使用)中产生的唯一代码。

As you can see no string setting or casting or echoing is taking place. 如您所见,没有字符串设置或强制转换或回显。

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

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. 更好的imo公开您的insert方法,并让您的代码用户告知初始化何时完成。 So something that should be used like: 所以应该使用类似以下内容的东西:

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

-update- -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 原因是php确实无法分辨两者之间的区别

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

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. 您当然可以通过使用其他包装方式来仅使用一个实例,但是我现在想到的唯一方式看起来要难看得多。

Im with PeeHaa, this makes no sense! 我和PeeHaa,这没有任何意义! :) :)

Only chance to have something magically happen after the last chain was used (without being able to look into the future) is a Destructor/Shutdown function OR a manually cast/call to insert() 在使用了最后一个链之后(无法展望未来)发生奇妙事情的唯一机会是Destructor / Shutdown函数或手动强制转换/调用insert()

You can also decide to implement this statically without using objects. 您还可以决定在不使用对象的情况下静态地实现此目的。

<?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

?>

Ok let's see a code example 好,让我们看一个代码示例

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

here we don't know what the last method would be and we need to trigger a kinda operation or event once we hit the end. 在这里,我们不知道最后一个方法是什么,一旦到达终点,我们就需要触发某种操作或事件。

According to data structure we can call this the LIFO stack. 根据数据结构,我们可以将其称为LIFO堆栈。 (Last in first out) (后进先出)

so how did i solve this on PHP? 那么我如何在PHP上解决这个问题呢?

// i did some back tracing //我做了一些追溯

... back to the __call function ...回到__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;
}

And whoolla we can call anything once we hit the bottom. 而且,一旦触底,我们就可以拨打任何电话。 *(Notice i use null once i am done with a variable, i come from C family where we manage memory ourselves) *(注意,一旦完成变量,我将使用null,我来自C家庭,我们自己管理内存)

Hope it helps you one way or the other. 希望它对您有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM