Rantai metode PHP?

170

Saya menggunakan PHP 5 dan saya pernah mendengar tentang fitur baru dalam pendekatan berorientasi objek, yang disebut 'metode chaining'. Apa itu sebenarnya? Bagaimana cara menerapkannya?

Sanjay Khatri
sumber
1
Saya akan mengatakan sebagian besar jika tidak semua pertanyaan itu tentang teknis tentang rantai, ini lebih khusus tentang bagaimana mencapainya.
Kristoffer Sall-Storgaard
@Kristoffer OP dapat dengan mudah menemukan bagaimana hal itu dicapai dari pertanyaan-pertanyaan ini.
Gordon
2
@ Kristoffer di samping itu, mencari metode chaining php di Google akan memberikan OP tutorial oleh Salathe sebagai hasil pertama. Saya tidak keberatan menjawab pertanyaan mudah, tetapi beberapa orang terlalu malas.
Gordon
6
Saya serahkan untuk teliti Anda, metode definitif chaining decision tree
rdlowrey

Jawaban:

333

Agaknya sederhana, Anda memiliki serangkaian metode mutator yang semuanya mengembalikan objek asli (atau lainnya), dengan begitu Anda dapat terus memanggil metode pada objek yang dikembalikan.

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

Ini menghasilkan "ab"

Cobalah online!

Kristoffer Sall-Storgaard
sumber
10
Ini juga kadang-kadang disebut sebagai Antarmuka Lancar
Nithesh Chandra
17
@Nitesh itu salah. Antarmuka Lancar menggunakan Metode Chaining sebagai mekanisme utama mereka, tetapi itu tidak sama . Metode rantai hanya mengembalikan objek host, sedangkan Antarmuka Lancar ditujukan untuk membuat DSL . Ex: $foo->setBar(1)->setBaz(2)vs $table->select()->from('foo')->where('bar = 1')->order('ASC). Yang terakhir ini mencakup beberapa objek.
Gordon
3
fungsi publik __toString () {return $ this-> str; } Ini tidak akan memerlukan metode terakhir "getStr ()" jika Anda sudah menggema rantai tersebut.
tfont
6
@ tfont Benar, tapi kemudian kami memperkenalkan metode sihir. Satu konsep pada satu waktu harus memadai.
Kristoffer Sall-Storgaard
3
Sejak PHP 5.4 itu bahkan mungkin untuk semuanya dalam satu baris:$a = (new fakeString())->addA()->addB()->getStr();
Philzen
48

Pada dasarnya, Anda mengambil objek:

$obj = new ObjectWithChainableMethods();

Panggil metode yang secara efektif melakukan a return $this;di akhir:

$obj->doSomething();

Karena mengembalikan objek yang sama, atau lebih tepatnya, referensi ke objek yang sama, Anda dapat melanjutkan memanggil metode dari kelas yang sama dari nilai pengembalian, seperti:

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

Itu dia, sungguh. Dua hal penting:

  1. Seperti yang Anda perhatikan, ini hanya PHP 5. Ini tidak akan berfungsi dengan baik di PHP 4 karena mengembalikan objek dengan nilai dan itu berarti Anda memanggil metode pada salinan objek yang berbeda, yang akan merusak kode Anda.

  2. Sekali lagi, Anda perlu mengembalikan objek dalam metode yang dapat dilewati:

    public function doSomething() {
        // Do stuff
        return $this;
    }
    
    public function doSomethingElse() {
        // Do more stuff
        return $this;
    }
BoltClock
sumber
Bisakah Anda melakukannya return &$thisdi PHP4?
alex
@alex: Saya tidak punya PHP 4 untuk diuji dengan sekarang, tapi saya cukup yakin tidak.
BoltClock
4
Saya juga tidak berpikir begitu, tetapi harusnya berhasil bukan? Mungkin jika PHP4 tidak begitu PHP4-ish.
alex
Anda bisa mendapatkan langkah-langkah sederhana lengkap dari metode chaining di techflirt.com/tutorials/oop-in-php/php-method-chaining.html
Ankur Kumar Singh
28

Coba kode ini:

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

?>
mwangaben
sumber
1
ini yang saya sebut penjelasan yang bagus ... metode chaining selalu membuatku merinding !!
MYNE
Bagaimana saya mengidentifikasi (di dalam metode) elemen pertama dan terakhir (panggilan) dalam rantai. Karena kadang-kadang ini sekarang hanya daftar operasi yang harus dilakukan secara berurutan, tetapi sesuatu yang harus dilakukan setelah mengumpulkan semua elemen. Seperti mengeksekusi query SQL di sini - tetapi waspadalah, Anda bisa melakukan banyak panggilan berantai pada satu objek! Firt dan terakhir di masing-masing.
Andris
12

Chaining metode berarti Anda dapat membuat panggilan metode panggilan:

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

Ini berarti bahwa method1 () perlu mengembalikan objek, dan method2 () diberikan hasil dari method1 (). Method2 () kemudian meneruskan nilai kembali ke method3 ().

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

Alex
sumber
5
Penjelasannya sedikit salah. Nilai kembali tidak diedarkan. Metode hanya mengembalikan objek host.
Gordon
@ Gordon Yah, objek host tidak dikembalikan. Benda apa pun bisa dikembalikan dan dirantai.
alexn
2
Maka saya berpendapat itu bukan metode chaining seperti yang didefinisikan oleh Fowler, mis. Membuat metode pengubah mengembalikan objek host sehingga beberapa pengubah dapat dipanggil dalam satu ekspresi. - jika Anda mengembalikan objek lain, kemungkinan besar Antarmuka Lancar :)
Gordon
Wow, saya sadar bahwa saya mengomentari kiriman yang hampir berusia 8 tahun .. Tapi tautan Anda yang Anda miliki di sana, mengarahkan ke beberapa situs web lain. Hanya fyi.
willbeeler
11

Cara lain untuk chaining metode statis:

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

Panggilan

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

echo "<br />";

echo Maker::words(['foo', 'bob', 'bar'])->concate('>')->get();
Rashedul Islam Sagor
sumber
6

Ada 49 baris kode yang memungkinkan Anda untuk menghubungkan metode pada array seperti ini:

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

Lihat artikel ini yang menunjukkan kepada Anda bagaimana cara menghubungkan semua fungsi tujuh puluh array_ PHP.

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

Lukas Dong
sumber
5
Ini sebenarnya bukan jawaban yang jauh dari tautan ke laman web dengan jawaban potensial.
faintsignal
-1

Jika Anda maksud metode chaining seperti dalam JavaScript (atau beberapa orang mengingat jQuery), mengapa tidak mengambil perpustakaan yang membawa dev itu. pengalaman dalam PHP? Misalnya Ekstra - https://dsheiko.github.io/extras/ Yang ini memperluas jenis PHP dengan metode JavaScript dan Garis Bawah dan menyediakan rangkaian:

Anda dapat rantai jenis tertentu:

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

atau

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

Atau Anda bisa menggunakan polimorfik:

<?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"
Dmitry Sheiko
sumber
Ini tidak benar-benar menjawab pertanyaan ("Apa itu metode chaining?"). Pertanyaan aslinya adalah 8 tahun dan sudah mendapat sejumlah jawaban yang lebih baik
GordonM
-1

Di bawah ini adalah model saya yang dapat ditemukan oleh ID dalam database. Metode with ($ data) adalah parameter tambahan saya untuk hubungan jadi saya mengembalikan $ this yang merupakan objek itu sendiri. Pada pengontrol saya, saya dapat mengaitkannya.

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);
    }
}
JuanBruno
sumber
dapatkah Anda menjelaskan apa yang dilakukannya?
ichimaru
ada penjelasan apa ini?
Patrick