PHP方法链接?


170

我正在使用PHP 5,并且听说过面向对象方法中的一项新功能,即“方法链接”。究竟是什么?如何实施?


1
我要说的是,即使不是所有这些问题,大多数都是关于链接的技术性的问题,更具体地说是关于如何实现链接的问题。
克里斯托弗·萨尔·​​斯托加德

@Kristoffer OP可以很容易地从这些问题中找到实现的方法。
戈登

2
@Kristoffer另外,在Google上搜索方法链接php会为OP提供Salathe教程是第一个结果。我不介意回答简单的问题,但是有些人太懒了。
Gordon 2010年

6
我谨请您仔细阅读
权威的

Answers:


333

实际上,它相当简单,您有一系列的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();

输出“ ab”

在线尝试!


10
有时也称为Fluent接口
Nithesh Chandra

17
@Nitesh不正确。Fluent接口使用“ 方法链接”作为其主要机制,但这并不相同。方法链接仅返回宿主对象,而Fluent接口旨在创建DSL。例如:$foo->setBar(1)->setBaz(2)vs $table->select()->from('foo')->where('bar = 1')->order('ASC)。后者跨越多个对象。
戈登

3
公共函数__toString(){return $ this-> str; 如果您已经在回显链,则不需要最后一个方法“ getStr()”。
tfont

6
@tfont是的,但随后我们介绍了魔术方法。一个概念一次就足够了。
Kristoffer Sall-Storgaard 2014年

3
自PHP 5.4起,甚至所有功能都可以在一行中完成:$a = (new fakeString())->addA()->addB()->getStr();
Philzen 2015年

48

基本上,您需要一个对象:

$obj = new ObjectWithChainableMethods();

调用一个有效地return $this;在最后执行a的方法:

$obj->doSomething();

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

$obj->doSomething()->doSomethingElse();

就是这样。两件重要的事情:

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

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

    public function doSomething() {
        // Do stuff
        return $this;
    }
    
    public function doSomethingElse() {
        // Do more stuff
        return $this;
    }

return &$this能用PHP4 做吗?
Alex

@alex:我现在没有要测试的PHP 4,但是我敢肯定没有。
BoltClock

4
我也没有这样的想法,但是应该正确吗?也许如果PHP4不是那么PHP4时代的话。
Alex


28

试试这个代码:

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

?>

1
这就是我所说的一个很好的解释。。。链接方法总是给我鸡皮!
MYNE

我如何(在方法内部)识别链中的第一个和最后一个元素(调用)。因为有时现在这只是要按顺序执行的操作的列表,但是应该在收集所有元素之后执行一些操作。就像在这里执行SQL查询一样-但要注意,您可以在一个对象上进行多个链接调用!首先和最后。
安德里斯

12

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

$object->method1()->method2()->method3()

这意味着method1()需要返回一个对象,并且method2()被赋予method1()的结果。然后,Method2()将返回值传递给method3()。

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


5
解释有点偏离。返回值不会传递。这些方法仅返回宿主对象。
戈登2010年

@戈登好吧,宿主对象没有被返回。任何对象都可以返回并链接。
alexn

2
然后,我认为这不是Fowler定义的方法链接,例如,使修饰符方法返回宿主对象,以便可以在单个表达式中调用多个修饰符。-如果您返回其他对象,则很有可能是Fluent接口:)
Gordon 2010年

哇,我意识到我正在评论一个已有近8年历史的帖子。但是您在那里的链接正在重定向到其他网站。只是
willbeeler

11

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

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

呼唤

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

echo "<br />";

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

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

请参阅本文,它向您展示了如何链接所有PHP的70个array_函数。

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


5
这实际上不是一个答案,而是指向具有潜在答案的网页的链接。
faintsignal

-1

如果您要像在JavaScript中那样链接方法(或者有些人要记住jQuery),那么为什么不选择带这个开发人员的库呢?PHP经验?例如Extras- https://dsheiko.github.io/extras/此代码使用JavaScript和Underscore方法扩展了PHP类型,并提供了链接:

您可以链接特定类型:

<?php
use \Dsheiko\Extras\Arrays;
// Chain of calls
$res = Arrays::chain([1, 2, 3])
    ->map(function($num){ return $num + 1; })
    ->filter(function($num){ return $num > 1; })
    ->reduce(function($carry, $num){ return $carry + $num; }, 0)
    ->value();

要么

<?php
use \Dsheiko\Extras\Strings;
$res = Strings::from( " 12345 " )
            ->replace("/1/", "5")
            ->replace("/2/", "5")
            ->trim()
            ->substr(1, 3)
            ->get();
echo $res; // "534"

或者,您可以进行多态操作:

<?php
use \Dsheiko\Extras\Any;

$res = Any::chain(new \ArrayObject([1,2,3]))
    ->toArray() // value is [1,2,3]
    ->map(function($num){ return [ "num" => $num ]; })
    // value is [[ "num" => 1, ..]]
    ->reduce(function($carry, $arr){
        $carry .= $arr["num"];
        return $carry;

    }, "") // value is "123"
    ->replace("/2/", "") // value is "13"
    ->then(function($value){
      if (empty($value)) {
        throw new \Exception("Empty value");
      }
      return $value;
    })
    ->value();
echo $res; // "13"

这并不能真正回答问题(“什么是方法链接?”)。同样,最初的问题已有8年历史,并且已经有了许多更好的答案
GordonM '18

-1

下面是我的模型,能够通过数据库中的ID查找。with($ data)方法是我用于关系的其他参数,因此我返回对象本身的$ this。在我的控制器上,我可以将其链接。

class JobModel implements JobInterface{

        protected $job;

        public function __construct(Model $job){
            $this->job = $job;
        }

        public function find($id){
            return $this->job->find($id);
        }

        public function with($data=[]){
            $this->job = $this->job->with($params);
            return $this;
        }
}

class JobController{
    protected $job;

    public function __construct(JobModel $job){
        $this->job = $job;
    }

    public function index(){
        // chaining must be in order
        $this->job->with(['data'])->find(1);
    }
}

你能解释一下这是做什么的吗?
ichimaru

有什么解释吗?
Patrick
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.