PHP method chaining?

拟墨画扇 提交于 2019-11-25 22:57:40

问题


I am using PHP 5 and I\'ve heard of a new featured in the object-oriented approach, called \'method chaining\'. What is it exactly? How do I implement it?


回答1:


Its rather simple really, you have a series of mutator methods that all returns the original (or other) objects, that way you can keep calling methods on the returned object.

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

This outputs "ab"

Try it online!




回答2:


Basically, you take an object:

$obj = new ObjectWithChainableMethods();

Call a method that effectively does a return $this; at the end:

$obj->doSomething();

Since it returns the same object, or rather, a reference to the same object, you can continue calling methods of the same class off the return value, like so:

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

That's it, really. Two important things:

  1. As you note, it's PHP 5 only. It won't work properly in PHP 4 because it returns objects by value and that means you're calling methods on different copies of an object, which would break your code.

  2. Again, you need to return the object in your chainable methods:

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



回答3:


Try this code:

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

?>



回答4:


Method chaining means that you can chain method calls:

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

This means that method1() needs to return an object, and method2() is given the result of method1(). Method2() then passes the return value to method3().

Good article: http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html




回答5:


Another Way for static method chaining :

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

Calling

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

echo "<br />";

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



回答6:


There are 49 lines of code which allows you to chain methods over arrays like this:

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

See this article which shows you how to chain all the PHP's seventy array_ functions.

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




回答7:


If you mean method chaining like in JavaScript (or some people keep in mind jQuery), why not just take a library that brings that dev. experience in PHP? For example Extras - https://dsheiko.github.io/extras/ This one extends PHP types with JavaScript and Underscore methods and provides chaining:

You can chain a particular type:

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

or

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

Alternatively you can go polymorphic:

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


Below is my model that is able to find by ID in the database. The with($data) method is my additional parameters for relationship so I return the $this which is the object itself. On my controller I am able to chain it.

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


来源:https://stackoverflow.com/questions/3724112/php-method-chaining

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!