PHP方法链接?

San*_*tri 156 php oop method-chaining

我正在使用PHP 5,我听说过面向对象方法中的一个新特性,称为"方法链".究竟是什么?我该如何实现它?

Kri*_*ard 315

它非常简单,你有一系列mutator方法都返回原始(或其他)对象,这样你就可以继续调用返回对象的方法.

<?php
class fakeString
{
    private $str;
    function __construct()
    {
        $this->str = "";
    }

    function addA()
    {
        $this->str .= "a";
        return $this;
    }

    function addB()
    {
        $this->str .= "b";
        return $this;
    }

    function getStr()
    {
        return $this->str;
    }
}


$a = new fakeString();


echo $a->addA()->addB()->getStr();
Run Code Online (Sandbox Code Playgroud)

输出"ab"

在线尝试!

  • @Nitesh这是不正确的.[Fluent Interfaces](http://www.martinfowler.com/bliki/FluentInterface.html)使用[Method Chaining](http://martinfowler.com/dslwip/MethodChaining.html)作为他们的主要机制,但是[它不是相同](http://en.wikipedia.org/wiki/Fluent_interface).链接方法只返回主机对象,而Fluent接口则旨在创建[DSL](http://en.wikipedia.org/wiki/Domain-specific_language).例如:`$ foo-> setBar(1) - > setBaz(2)`vs` $ table-> select() - > from('foo') - > where('bar = 1') - > order(' ASC)`.后者跨越多个对象. (17认同)
  • 这有时也称为Fluent界面 (10认同)
  • @tfont是的,但后来我们引入了魔术方法.一次一个概念就足够了. (6认同)
  • public function __toString(){return $ this-> str; 如果您已经回显链,这将不需要最后一个方法"getStr()". (3认同)
  • 从PHP 5.4开始,它甚至可以在一行中***:$ $ =(new fakeString()) - > addA() - > addB() - > getStr();` (2认同)

Bol*_*ock 43

基本上,你拿一个对象:

$obj = new ObjectWithChainableMethods();
Run Code Online (Sandbox Code Playgroud)

调用return $this;最终有效执行的方法:

$obj->doSomething();
Run Code Online (Sandbox Code Playgroud)

由于它返回相同的对象,或者更确切地说是同一对象的引用,因此可以继续从返回值中调用同一类的方法,如下所示:

$obj->doSomething()->doSomethingElse();
Run Code Online (Sandbox Code Playgroud)

就是这样,真的.两件重要的事情:

  1. 如你所知,它只是PHP 5.它在PHP 4中无法正常工作,因为它按值返回对象,这意味着您在对象的不同副本上调用方法,这会破坏您的代码.

  2. 同样,您需要在可链接方法中返回对象:

    public function doSomething() {
        // Do stuff
        return $this;
    }
    
    public function doSomethingElse() {
        // Do more stuff
        return $this;
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • 我也不这么认为,但它应该*正常工作?也许如果PHP4不是那么PHP4-ish. (4认同)

mwa*_*ben 24

试试这段代码:

<?php
class DBManager
{
    private $selectables = array();
    private $table;
    private $whereClause;
    private $limit;

    public function select() {
        $this->selectables = func_get_args();
        return $this;
    }

    public function from($table) {
        $this->table = $table;
        return $this;
    }

    public function where($where) {
        $this->whereClause = $where;
        return $this;
    }

    public function limit($limit) {
        $this->limit = $limit;
        return $this;
    }

    public function result() {
        $query[] = "SELECT";
        // if the selectables array is empty, select all
        if (empty($this->selectables)) {
            $query[] = "*";  
        }
        // else select according to selectables
        else {
            $query[] = join(', ', $this->selectables);
        }

        $query[] = "FROM";
        $query[] = $this->table;

        if (!empty($this->whereClause)) {
            $query[] = "WHERE";
            $query[] = $this->whereClause;
        }

        if (!empty($this->limit)) {
            $query[] = "LIMIT";
            $query[] = $this->limit;
        }

        return join(' ', $query);
    }
}

// Now to use the class and see how METHOD CHAINING works
// let us instantiate the class DBManager
$testOne = new DBManager();
$testOne->select()->from('users');
echo $testOne->result();
// OR
echo $testOne->select()->from('users')->result();
// both displays: 'SELECT * FROM users'

$testTwo = new DBManager();
$testTwo->select()->from('posts')->where('id > 200')->limit(10);
echo $testTwo->result();
// this displays: 'SELECT * FROM posts WHERE id > 200 LIMIT 10'

$testThree = new DBManager();
$testThree->select(
    'firstname',
    'email',
    'country',
    'city'
)->from('users')->where('id = 2399');
echo $testThree->result();
// this will display:
// 'SELECT firstname, email, country, city FROM users WHERE id = 2399'

?>
Run Code Online (Sandbox Code Playgroud)

  • 这就是我所说的一个很好的解释……链接方法总是让我起鸡皮疙瘩!! (2认同)

ale*_*exn 11

方法链接意味着您可以链接方法调用:

$object->method1()->method2()->method3()
Run Code Online (Sandbox Code Playgroud)

这意味着method1()需要返回一个对象,而method2()则给出了method1()的结果.然后,Method2()将返回值传递给method3().

好文章:http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html

  • 解释有点过时了.返回值不会传递.这些方法只返回宿主对象. (5认同)
  • 然后我认为这不是Fowler定义的方法链接,例如[Make modifier方法返回宿主对象,以便可以在单个表达式中调用多个修饰符.](http://martinfowler.com/dslwip/MethodChaining.html) - 如果你返回其他对象,它更可能是一个流畅的界面:) (2认同)

Ras*_*gor 9

静态方法链接的另一种方法:

class Maker 
{
    private static $result      = null;
    private static $delimiter   = '.';
    private static $data        = [];

    public static function words($words)
    {
        if( !empty($words) && count($words) )
        {
            foreach ($words as $w)
            {
                self::$data[] = $w;
            }
        }        
        return new static;
    }

    public static function concate($delimiter)
    {
        self::$delimiter = $delimiter;
        foreach (self::$data as $d)
        {
            self::$result .= $d.$delimiter;
        }
        return new static;
    }

    public static function get()
    {
        return rtrim(self::$result, self::$delimiter);
    }    
}
Run Code Online (Sandbox Code Playgroud)

调用

echo Maker::words(['foo', 'bob', 'bar'])->concate('-')->get();

echo "<br />";

echo Maker::words(['foo', 'bob', 'bar'])->concate('>')->get();
Run Code Online (Sandbox Code Playgroud)


小智 6

有49行代码允许您将方法链接到数组,如下所示:

$fruits = new Arr(array("lemon", "orange", "banana", "apple"));
$fruits->change_key_case(CASE_UPPER)->filter()->walk(function($value,$key) {
     echo $key.': '.$value."\r\n";
});
Run Code Online (Sandbox Code Playgroud)

请参阅本文,其中介绍了如何链接所有PHP的70个array_函数.

http://domexception.blogspot.fi/2013/08/php-magic-methods-and-arrayobject.html

  • 这不是一个真正的答案,而是指向具有潜在答案的网页的链接. (5认同)