วิธีการผูกมัด PHP?


170

ฉันใช้ PHP 5 และฉันเคยได้ยินเรื่องใหม่เกี่ยวกับวิธีการเชิงวัตถุที่เรียกว่า 'การโยงวิธีการ' มันคืออะไรกันแน่? ฉันจะใช้งานได้อย่างไร


1
ฉันจะบอกว่าส่วนใหญ่ถ้าไม่ใช่คำถามทั้งหมดนั้นเกี่ยวกับความรู้ด้านเทคนิคเกี่ยวกับการผูกมัดมันจะเจาะจงมากขึ้นเกี่ยวกับวิธีการทำให้สำเร็จ
Kristoffer Sall-Storgaard

@ Kristoffer the OP สามารถค้นพบได้อย่างง่ายดายว่าเป็นไปได้อย่างไรจากคำถามเหล่านี้
Gordon

2
@Kristoffer นอกจากนี้การค้นหาวิธีการผูกมัด php บน Googleจะได้รับการกวดวิชา OP โดยSalatheเป็นผลแรก ฉันไม่รังเกียจที่จะตอบคำถามง่าย ๆ แต่บางคนขี้เกียจเกินไป
Gordon

6
ฉันส่งใบสมัครของคุณไปแล้วต้นไม้แห่งการตัดสินใจที่ถูกต้อง
rdlowrey

คำตอบ:


333

มันค่อนข้างง่ายจริงๆคุณมีชุดของวิธีการเปลี่ยนแปลงที่ทุกคนส่งกลับวัตถุดั้งเดิม (หรืออื่น ๆ ) วิธีที่คุณสามารถให้วิธีการโทรบนวัตถุที่ส่งคืน

<?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
บางครั้งก็เรียกว่าส่วนต่อ
ประสาน

17
@Nitesh ที่ไม่ถูกต้อง การเชื่อมต่อได้อย่างคล่องแคล่วใช้วิธีการผูกมัดเป็นกลไกหลักของพวกเขา แต่ก็ไม่เหมือนกัน วิธีการผูกมัดเพียงแค่ส่งกลับวัตถุโฮสต์ในขณะที่การเชื่อมต่อคล่องแคล่วมีวัตถุประสงค์ที่จะสร้างDSL Ex: VS$foo->setBar(1)->setBaz(2) $table->select()->from('foo')->where('bar = 1')->order('ASC)หลังมีช่วงหลายวัตถุ
Gordon

3
ฟังก์ชั่นสาธารณะ __toString () {return $ this-> str; } สิ่งนี้จะไม่ต้องใช้วิธีการสุดท้าย "getStr ()" ถ้าคุณสะท้อนโซ่แล้ว
tfont

6
@tfont True แต่จากนั้นเราจะแนะนำวิธีการทางเวทมนตร์ แนวคิดหนึ่งครั้งควรเพียงพอ
Kristoffer Sall-Storgaard

3
นับตั้งแต่ PHP 5.4 เป็นไปได้สำหรับทุกสิ่งในบรรทัดเดียว:$a = (new fakeString())->addA()->addB()->getStr();
Philzen

48

โดยทั่วไปคุณใช้วัตถุ:

$obj = new ObjectWithChainableMethods();

เรียกวิธีการที่มีประสิทธิภาพreturn $this;เมื่อสิ้นสุด:

$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 &$thisPHP4 ได้ไหม?
alex

@alex: ฉันไม่มี PHP 4 ที่จะทดสอบในตอนนี้ แต่ฉันค่อนข้างแน่ใจว่าไม่
BoltClock

4
ฉันไม่คิดอย่างนั้น แต่มันควรจะทำงานใช่ไหม บางทีถ้า PHP4 ไม่เป็นเช่นนั้น PHP4-ish
alex

คุณสามารถรับขั้นตอนง่าย ๆ ของวิธีการผูกมัดที่techflirt.com/tutorials/oop-in-php/php-method-chaining.html
Ankur Kumar Singh

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 ที่นี่ - แต่ระวังคุณสามารถโทรหลายสายในวัตถุเดียว! Firt และสุดท้ายในแต่ละ
Andris

12

ผูกมัดวิธีการหมายความว่าคุณสามารถเชื่อมโยงวิธีการโทร:

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

นี่หมายความว่า method1 () ต้องส่งคืนออบเจ็กต์และ method2 () จะได้รับผลลัพธ์ของ method1 () วิธีที่ 2 () จากนั้นส่งผ่านค่าตอบแทนไปที่ method3 ()

บทความที่ดี: http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html


5
คำอธิบายนั้นออกไปเล็กน้อย ค่าส่งคืนจะไม่ผ่าน วิธีการก็จะส่งคืนวัตถุโฮสต์
Gordon

@Gordon ดีวัตถุโฮสต์จะไม่ถูกส่งกลับ วัตถุใด ๆ ที่สามารถส่งคืนและถูกผูกมัด
alexn

2
จากนั้นฉันจะโต้แย้งว่าไม่ใช่วิธีการผูกมัดตามที่กำหนดโดย Fowler เช่นMake method modifier คืนค่าวัตถุโฮสต์เพื่อให้ตัวดัดแปลงหลายตัวสามารถเรียกใช้ในนิพจน์เดียว - หากคุณส่งคืนวัตถุอื่น ๆ ก็เป็นไปได้มากขึ้นว่าอินเทอร์เฟซ Fluent :)
Gordon

ว้าวฉันรู้ว่าฉันกำลังแสดงความคิดเห็นในโพสต์เก่าเกือบ 8 ปี แต่ลิงค์ของคุณที่คุณอยู่นั้นกำลังเปลี่ยนเส้นทางไปยังเว็บไซต์อื่น เพียงแค่ fyi
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";
});

ดูบทความนี้ซึ่งแสดงวิธีการเชื่อมโยงฟังก์ชั่น array_ เจ็ดสิบของ PHP ทั้งหมด

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


5
นี่ไม่ใช่คำตอบที่จริงมากเท่ากับลิงก์ไปยังหน้าเว็บที่มีคำตอบที่เป็นไปได้
faintsignal

-1

หากคุณหมายถึงวิธีการผูกมัดเช่นใน JavaScript (หรือบางคนจำ jQuery) ทำไมไม่ใช้ห้องสมุดที่นำ dev นั้น มีประสบการณ์เกี่ยวกับ PHP ไหม? ตัวอย่างเช่น Extras - https://dsheiko.github.io/extras/ อันนี้จะขยายประเภท PHP ด้วย JavaScript และวิธีขีดล่างและให้การผูกมัด:

คุณสามารถโยงประเภทเฉพาะ:

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

หรือคุณสามารถไป 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 ปีและได้รับคำตอบที่ดีกว่าจำนวนมากแล้ว
GordonM

-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

คำอธิบายใด ๆ สิ่งนี้ทำอะไร?
แพทริค
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.