Verkettung der PHP-Methode?

170

Ich verwende PHP 5 und habe von einer neuen Funktion im objektorientierten Ansatz gehört, die als "Methodenverkettung" bezeichnet wird. Was ist es genau? Wie implementiere ich es?

Sanjay Khatri
quelle
1
Ich würde sagen, die meisten, wenn nicht alle dieser Fragen beziehen sich auf technische Aspekte der Verkettung. Hier geht es insbesondere darum, wie dies erreicht werden kann.
Kristoffer Sall-Storgaard
@Kristoffer das OP hätte leicht herausfinden können, wie es aus diesen Fragen erreicht wird.
Gordon
2
@Kristoffer Darüber hinaus hätte die Suche nach Methodenverkettung bei Google dem OP als erstes Ergebnis ein Tutorial von Salathe gegeben . Es macht mir nichts aus, einfache Fragen zu beantworten, aber einige Leute sind einfach zu faul.
Gordon
6
Ich
lege

Antworten:

333

Es ist wirklich ziemlich einfach, Sie haben eine Reihe von Mutator-Methoden , die alle die ursprünglichen (oder andere) Objekte zurückgeben. Auf diese Weise können Sie weiterhin Methoden für das zurückgegebene Objekt aufrufen.

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

Dies gibt "ab" aus

Probieren Sie es online aus!

Kristoffer Sall-Storgaard
quelle
10
Dies wird manchmal auch als Fluent Interface
Nithesh Chandra
17
@Nitesh das ist falsch. Fließende Schnittstellen verwenden die Methodenverkettung als primären Mechanismus, aber es ist nicht dasselbe . Die Methodenverkettung gibt einfach das Hostobjekt zurück, während eine Fluent-Schnittstelle darauf abzielt, ein DSL zu erstellen . Ex: $foo->setBar(1)->setBaz(2)vs $table->select()->from('foo')->where('bar = 1')->order('ASC). Letzteres umfasst mehrere Objekte.
Gordon
3
öffentliche Funktion __toString () {return $ this-> str; } Dies erfordert nicht die letzte Methode "getStr ()", wenn Sie die Kette bereits wiedergeben.
tfont
6
@tfont Stimmt, aber dann führen wir magische Methoden ein. Jeweils ein Konzept sollte ausreichen.
Kristoffer Sall-Storgaard
3
Seit PHP 5.4 ist sogar alles in einer Zeile möglich:$a = (new fakeString())->addA()->addB()->getStr();
Philzen
48

Grundsätzlich nehmen Sie ein Objekt:

$obj = new ObjectWithChainableMethods();

Rufen Sie eine Methode auf, die return $this;am Ende effektiv a ausführt:

$obj->doSomething();

Da es dasselbe Objekt oder vielmehr einen Verweis auf dasselbe Objekt zurückgibt , können Sie weiterhin Methoden derselben Klasse vom Rückgabewert aufrufen, wie folgt:

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

Das war's wirklich. Zwei wichtige Dinge:

  1. Wie Sie bemerken, ist es nur PHP 5. In PHP 4 funktioniert es nicht richtig, da Objekte nach Wert zurückgegeben werden. Dies bedeutet, dass Sie Methoden für verschiedene Kopien eines Objekts aufrufen, wodurch Ihr Code beschädigt wird.

  2. Auch hier müssen Sie das Objekt in Ihren verkettbaren Methoden zurückgeben:

    public function doSomething() {
        // Do stuff
        return $this;
    }
    
    public function doSomethingElse() {
        // Do more stuff
        return $this;
    }
BoltClock
quelle
Könnten Sie return &$thisin PHP4 tun ?
Alex
@alex: Ich habe momentan kein PHP 4 zum Testen, aber ich bin mir ziemlich sicher, dass dies nicht der Fall ist.
BoltClock
4
Das habe ich auch nicht gedacht, aber es sollte funktionieren, oder? Vielleicht, wenn PHP4 nicht so PHP4-ish wäre.
Alex
Die vollständigen einfachen Schritte der Methodenverkettung finden Sie unter techflirt.com/tutorials/oop-in-php/php-method-chaining.html
Ankur Kumar Singh
28

Versuchen Sie diesen 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'

?>
mwangaben
quelle
1
Das nenne ich eine gute Erklärung ... Verkettungsmethoden geben mir immer Gänsehaut !!
MYNE
Wie ich (innerhalb der Methode) das erste und das letzte Element (Aufrufe) in der Kette identifiziere. Denn manchmal ist dies nur noch eine Liste von Operationen, die in der richtigen Reihenfolge ausgeführt werden sollen, aber etwas, das nach dem Sammeln aller Elemente ausgeführt werden sollte. Wie beim Ausführen einer SQL-Abfrage hier - aber Vorsicht, Sie können mehrere verkettete Aufrufe für ein Objekt ausführen! Firt und zuletzt in jedem.
Andris
12

Methodenverkettung bedeutet, dass Sie Methodenaufrufe verketten können:

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

Dies bedeutet, dass method1 () ein Objekt zurückgeben muss und method2 () das Ergebnis von method1 () erhält. Methode2 () übergibt dann den Rückgabewert an Methode3 ().

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

alexn
quelle
5
Die Erklärung ist etwas abwegig. Die Rückgabewerte werden nicht weitergegeben. Die Methoden geben einfach das Host-Objekt zurück.
Gordon
@ Gordon Nun, das Host-Objekt wird nicht zurückgegeben. Jedes Objekt kann zurückgegeben und verkettet werden.
Alexn
2
Dann würde ich argumentieren, dass es sich nicht um eine von Fowler definierte Methodenverkettung handelt , z. B. lassen Modifikatormethoden das Hostobjekt zurückgeben, sodass mehrere Modifikatoren in einem einzigen Ausdruck aufgerufen werden können. - Wenn Sie andere Objekte zurückgeben, ist es wahrscheinlicher eine fließende Schnittstelle :)
Gordon
Wow, mir ist klar, dass ich einen fast 8 Jahre alten Beitrag kommentiere. Aber Ihr Link, den Sie dort haben, leitet zu einer anderen Website weiter. Nur zur Info.
Willbeeler
11

Ein anderer Weg zur Verkettung statischer Methoden:

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

Berufung

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

echo "<br />";

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

Es gibt 49 Codezeilen, mit denen Sie Methoden über Arrays wie folgt verketten können:

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

In diesem Artikel erfahren Sie, wie Sie alle siebzig array_-Funktionen des PHP verketten.

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

Lukas Dong
quelle
5
Dies ist weniger eine Antwort als vielmehr ein Link zu einer Webseite mit einer möglichen Antwort.
Faintsignal
-1

Wenn Sie Methodenverkettung wie in JavaScript meinen (oder einige Leute denken an jQuery), warum nicht einfach eine Bibliothek nehmen, die diesen Entwickler bringt? Erfahrung in PHP? Zum Beispiel Extras - https://dsheiko.github.io/extras/ Dieser erweitert PHP-Typen mit JavaScript- und Unterstreichungsmethoden und bietet Verkettung:

Sie können einen bestimmten Typ verketten:

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

oder

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

Alternativ können Sie polymorph gehen:

<?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
quelle
Dies beantwortet die Frage nicht wirklich ("Was ist Methodenverkettung?"). Auch die ursprüngliche Frage ist 8 Jahre alt und hat bereits eine Reihe von besseren Antworten
GordonM
-1

Unten ist mein Modell, das anhand der ID in der Datenbank gefunden werden kann. Die with ($ data) -Methode ist mein zusätzlicher Parameter für die Beziehung, daher gebe ich das $ this zurück, das das Objekt selbst ist. Auf meinem Controller kann ich es verketten.

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
quelle
Kannst du erklären, was das macht?
Ichimaru
Irgendeine Erklärung, was das macht?
Patrick