检查调用是否为方法链接


Check if call is 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;
}

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

取而代之的是,您可以随时返回$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;
    }
}

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

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