PHP विधि chaining?


170

मैं PHP 5 का उपयोग कर रहा हूं और मैंने ऑब्जेक्ट-ओरिएंटेड अप्रोच में एक नए फीचर के बारे में सुना है, जिसे 'मेथड चेनिंग' कहा जाता है। हकीकत में यह क्या है? मैं इसे कैसे लागू करूं?


1
मैं सबसे कहूंगा कि अगर उन सभी सवालों के बारे में तकनीकीकरण के बारे में नहीं हैं, तो यह विशेष रूप से इसे प्राप्त करने के बारे में अधिक है।
क्रिस्टोफ़र साल्-स्टोर्गार्ड

@ कृस्टोफ़र ओपी आसानी से पता लगा सकता था कि इन सवालों से कैसे हासिल किया जाता है।
गॉर्डन

2
@ इसके अलावा, क्रिस्‍टोफर ने Google पर php chaining की विधि की खोज करते हुए, ओपी को सलाथे द्वारा पहले ही परिणाम के रूप में एक ट्यूटोरियल दिया । मुझे आसान सवालों के जवाब देने में कोई आपत्ति नहीं है, लेकिन कुछ लोग बहुत आलसी हैं।
गॉर्डन

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

यह "अब" आउटपुट

इसे ऑनलाइन आज़माएं!


10
इसे कभी-कभी धाराप्रवाह इंटरफ़ेस के रूप में भी संदर्भित किया जाता है
नितेश चंद्र

17
@ नितेश जो गलत है। धाराप्रवाह इंटरफेस उनके प्राथमिक तंत्र के रूप में विधि जंजीर का उपयोग करते हैं , लेकिन यह समान नहीं है । विधि श्रृंखलन केवल मेजबान वस्तु देता है, जबकि एक धाराप्रवाह इंटरफ़ेस एक डीएसएल बनाने के उद्देश्य से है । Ex: $foo->setBar(1)->setBaz(2)बनाम $table->select()->from('foo')->where('bar = 1')->order('ASC)। उत्तरार्द्ध कई वस्तुओं को फैलाता है।
गॉर्डन

3
सार्वजनिक समारोह __toString () {$ $ इस-> str; } यदि आपको पहले से ही चेन की गूंज सुनाई दे रही है तो इसके लिए अंतिम विधि "getStr ()" की आवश्यकता नहीं होगी।
tfont

6
@tfont True, लेकिन फिर हम जादू के तरीकों का परिचय दे रहे हैं। एक समय में एक अवधारणा पर्याप्त होनी चाहिए।
क्रिस्टोफ़र सॉल-स्टोर्गार्ड

3
PHP 5.4 के बाद से यह एक पंक्ति में सब कुछ संभव है :$a = (new fakeString())->addA()->addB()->getStr();
फिलजेन

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: मेरे पास अभी परीक्षण करने के लिए PHP 4 नहीं है, लेकिन मुझे पूरा यकीन है कि नहीं।
BoltClock

4
मैंने ऐसा नहीं सोचा था, लेकिन यह सही काम करना चाहिए ? शायद अगर PHP4 तो PHP4-ish नहीं था।
एलेक्स


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
यह वही है जिसे मैं एक अच्छी व्याख्या कहता हूं ... तरीकों का पीछा करते हुए हमेशा मुझे goosebumbs देता है !!
MYNE

मैं कैसे (विधि के अंदर) श्रृंखला में पहले और अंतिम तत्वों (कॉल) की पहचान करता हूं। क्योंकि कभी-कभी यह अब केवल क्रम में निष्पादित होने वाली कार्रवाइयों की एक सूची है, लेकिन कुछ ऐसा जो सभी तत्वों को इकट्ठा करने के बाद किया जाना चाहिए। यहां SQL क्वेरी निष्पादित करने की तरह - लेकिन सावधान रहें, आप एक ऑब्जेक्ट पर कई जंजीर कॉल कर सकते हैं! प्रत्येक में फ़र्ट और अंतिम।
एंड्रीस

12

मेथड चेनिंग का मतलब है कि आप चेन मेथड कॉल कर सकते हैं:

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

इसका मतलब यह है कि मेथड 1 () को एक ऑब्जेक्ट वापस करने की आवश्यकता है, और मेथड 2 () मेथड 1 () का परिणाम दिया गया है। Method2 () तब मेथड 3 () में रिटर्न वैल्यू पास करता है।

अच्छा लेख: http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html


5
स्पष्टीकरण थोड़ा हटकर है। रिटर्न मानों को पास नहीं किया जाता है। विधियाँ केवल होस्ट ऑब्जेक्ट लौटाती हैं।
गॉर्डन

@Gordon खैर, मेजबान वस्तु वापस नहीं है। किसी भी वस्तु को वापस लौटाया जा सकता है।
एलेक्स

2
तब मैं तर्क देता हूं कि यह फाउलर द्वारा परिभाषित विधि का पीछा नहीं कर रहा है, जैसे कि संशोधक तरीके मेजबान वस्तु को वापस करें ताकि एक ही अभिव्यक्ति में कई संशोधक लगाए जा सकें। - यदि आप अन्य वस्तुओं को वापस करते हैं, तो यह अधिक संभावना है कि एक धाराप्रवाह इंटरफ़ेस :)
गॉर्डन

वाह, मुझे एहसास है कि मैं लगभग 8 साल पुरानी पोस्ट पर टिप्पणी कर रहा हूं .. लेकिन आपका लिंक जो आपके पास है, वह किसी न किसी वेबसाइट पर रीडायरेक्ट कर रहा है। सिर्फ आपकी जानकारी के लिए।
विलबेलर

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 के सत्तर array_ फ़ंक्शन को कैसे चेन करें।

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


5
यह वास्तव में एक जवाब नहीं है इतना संभावित जवाब के साथ एक वेबपेज के लिए एक कड़ी के रूप में।
faintsignal

-1

यदि आप जावास्क्रिप्ट में (या कुछ लोग jQuery को ध्यान में रखते हैं) की तरह विधि का मतलब है, तो बस एक पुस्तकालय क्यों नहीं है जो उस देव को लाता है। PHP में अनुभव? उदाहरण के लिए एक्स्ट्रा - https://dsheiko.github.io/extras/ यह जावास्क्रिप्ट और अंडरस्कोर विधियों के साथ 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 साल पुराना है और पहले से ही कई बेहतर जवाब मिल गया है
गॉर्डन

-1

नीचे मेरा मॉडल है जो डेटाबेस में आईडी द्वारा खोजने में सक्षम है। ($ डेटा) विधि के साथ मेरे रिश्ते के लिए अतिरिक्त पैरामीटर हैं, इसलिए मैं इस $ को वापस करता हूं जो कि स्वयं वस्तु है। अपने कंट्रोलर पर मैं इसे चेन करने में सक्षम हूं।

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

क्या आप बता सकते हैं कि यह क्या करता है?
इचिमारू

किसी भी स्पष्टीकरण यह क्या करता है?
पैट्रिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.