检查呼叫是否为方法链接

时间:2015-01-30 13:09:58

标签: php method-chaining

是否可以知道方法调用是否来自方法链接?
例如,我有下面的class

class Test{
    protected $string = '123';

    public function a($string){
        $this->string .= $string;

        if(method chain){
            return $this;
        }else{
            return $this->string;
        }
    }

    public function b($string){
        $this->string .= $string;

        if(method chain){
            return $this;
        }else{
            return $this->string;
        }
    }
}

结果:

$test = new Test();
echo $test->a('000'); // 123000
echo $test->a('000')->b('www'); // 123000www

更新
我最终创建了一个exec()方法来告诉不再调用方法。

public function exec(){
    return $this->string;
}

2 个答案:

答案 0 :(得分:2)

这是不可能的,因为你不知道将使用方法结果的上下文。

取而代之的是,您可以随时返回$this只使用__toString方法来返回$string

class Test{
    protected $string = '123';

    public function a($string){
        $this->string .= $string;
        return $this;
    }

    public function b($string){
        $this->string .= $string;
        return $this;
    }

    public function __toString() {
        return $this->string;
    }
}

然后,如果你要回显你的价值 - 它将把它用作一个字符串,否则你将处理一个对象。

答案 1 :(得分:0)

PHP确实提供了debug_backtrace来检索每个已经使用文件位置和行号调用的函数。但这不会给出下一个函数调用。

通过使用文件位置和行号,我们可以解析源文件并获取链。

下面的getChains函数将以某种编码风格工作。

<?php

$abc = new Methods;
echo($abc->minus(12)->plus(32)); // output: -12+32

echo(
    $abc->plus(84)
    ->minus(63)
); // output: +84-63

class Methods{
    private $data = '';
    private $chains = false;

    public function minus($val){
        $this->data .= '-'.$val;
        return $this->exec('minus');
    }

    public function plus($val){
        $this->data .= '+'.$val;
        return $this->exec('plus');
    }

    private function exec($from){
        // Check if this is the first chain
        if($this->chains === false){
            $this->getChains();
        }

        // Remove the first chain as it's
        // already being called
        if($this->chains[0] === $from){
            array_shift($this->chains);
        }
        else
            die("Can't parse your chain");

        // Check if this is the last chain
        if(count($this->chains) === 0){
            $copy = $this->data;

            // Clear data
            $this->chains = false;
            $this->data = '';

            return $copy;
        }

        // If not then continue the chain
        return $this;
    }

    private function getChains(){
        $temp = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

        // Find out who called the function
        for ($i=0; $i < count($temp); $i++) { 
            if($temp[$i]['function'] === 'exec'){
                $temp = $temp[$i + 1];
                break;
            }
        }

        // Prepare variable
        $obtained = '';
        $current = 1;

        // Open that source and find the chain
        $handle = fopen($temp['file'], "r");
        if(!$handle) return false;

        while(($text = fgets($handle)) !== false){
            if($current >= $temp['line']){
                $obtained .= $text;

                // Find break
                if(strrpos($text, ';') !== false)
                    break;
            }
            $current++;
        }

        fclose($handle);
        preg_match_all('/>(\w.*?)\(/', $obtained, $matches);
        $this->chains = $matches[1];
        return true;
    }
}