Concatenamento del metodo PHP?


170

Sto usando PHP 5 e ho sentito parlare di una nuova funzionalità dell'approccio orientato agli oggetti, chiamato "metodo concatenamento". Che cosa è esattamente? Come lo implemento?


1
Direi che la maggior parte se non tutte quelle domande riguardano tecnicismi riguardanti il ​​concatenamento, questo è più specificamente su come raggiungerlo.
Kristoffer Sall-Storgaard,

@Kristoffer l'OP avrebbe potuto facilmente scoprire come si ottiene da queste domande.
Gordon,

2
@Kristoffer, inoltre, la ricerca del metodo di concatenamento di php su Google avrebbe dato all'OP un tutorial di Salathe come primo risultato. Non mi dispiace rispondere a domande facili, ma alcune persone sono troppo pigre.
Gordon,

Risposte:


334

È piuttosto semplice, hai una serie di metodi mutatori che restituiscono tutti gli oggetti originali (o altri), in questo modo puoi continuare a chiamare metodi sull'oggetto restituito.

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

Questo genera "ab"

Provalo online!


11
A volte viene anche definita interfaccia fluida
Nithesh Chandra,

18
@Nitesh che non è corretto. Le interfacce fluide usano il metodo di concatenamento come meccanismo principale, ma non è lo stesso . Il concatenamento dei metodi restituisce semplicemente l'oggetto host, mentre un'interfaccia fluida ha lo scopo di creare un DSL . Es: $foo->setBar(1)->setBaz(2)vs $table->select()->from('foo')->where('bar = 1')->order('ASC). Quest'ultimo si estende su più oggetti.
Gordon,

3
funzione pubblica __toString () {return $ this-> str; } Questo non richiederà l'ultimo metodo "getStr ()" se stai già facendo eco alla catena.
martedì

6
@tfont True, ma poi stiamo introducendo metodi magici. Un concetto alla volta dovrebbe essere sufficiente.
Kristoffer Sall-Storgaard,

3
Dal momento che PHP 5.4 è persino possibile tutto in una riga:$a = (new fakeString())->addA()->addB()->getStr();
Philzen

48

Fondamentalmente, prendi un oggetto:

$obj = new ObjectWithChainableMethods();

Chiama un metodo che esegua effettivamente un return $this;alla fine:

$obj->doSomething();

Poiché restituisce lo stesso oggetto, o meglio, un riferimento allo stesso oggetto, puoi continuare a chiamare metodi della stessa classe dal valore restituito, in questo modo:

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

Questo è tutto, davvero. Due cose importanti:

  1. Come noti, è solo PHP 5. Non funzionerà correttamente in PHP 4 perché restituisce oggetti in base al valore e ciò significa che stai chiamando metodi su diverse copie di un oggetto, il che infrange il tuo codice.

  2. Ancora una volta, è necessario restituire l'oggetto nei metodi concatenabili:

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

Potresti fare return &$thisin PHP4?
alex,

@alex: Non ho PHP 4 con cui provare adesso, ma sono quasi sicuro di no.
BoltClock

4
Neanche io la pensavo così, ma dovrebbe funzionare bene? Forse se PHP4 non fosse così PHP4-ish.
alex,

Puoi ottenere i semplici passaggi completi del concatenamento del metodo su techflirt.com/tutorials/oop-in-php/php-method-chaining.html
Ankur Kumar Singh

28

Prova questo codice:

<?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
questa è quella che chiamo una buona spiegazione ... i metodi di concatenamento mi danno sempre la pelle d'oca !!
MYNE,

Come identifico (all'interno del metodo) il primo e l'ultimo elemento (chiamata) nella catena. Perché a volte questo è solo un elenco di operazioni da eseguire in ordine, ma qualcosa che dovrebbe essere fatto dopo aver raccolto tutti gli elementi. Come eseguire una query SQL qui, ma attenzione, è possibile effettuare più chiamate concatenate su un oggetto! Firtare e ultimo in ciascuno.
Andris,

12

Il concatenamento dei metodi significa che è possibile concatenare le chiamate ai metodi:

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

Ciò significa che method1 () deve restituire un oggetto e method2 () riceve il risultato di method1 (). Method2 () quindi passa il valore restituito a method3 ().

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


5
La spiegazione è un po 'fuori. I valori restituiti non vengono passati. I metodi restituiscono semplicemente l'oggetto host.
Gordon,

@Gordon Bene, l'oggetto host non viene restituito. Qualsiasi oggetto può essere restituito e incatenato.
alex

2
Quindi direi che non è il concatenamento di metodi come definito da Fowler, ad esempio i metodi di modifica del ritorno restituiscono l'oggetto host in modo che più modificatori possano essere invocati in una singola espressione. - se restituisci altri oggetti, è più probabile un'interfaccia fluida :)
Gordon,

Wow, mi rendo conto che sto commentando un post di quasi 8 anni .. Ma il tuo link che hai lì sta reindirizzando a qualche altro sito web. Fyi.
Willbeeler,

11

Un altro modo per concatenare metodi statici:

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

chiamata

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

echo "<br />";

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

6

Esistono 49 righe di codice che consentono di concatenare i metodi su array come questo:

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

Vedi questo articolo che mostra come concatenare tutte le settanta funzioni array_ del PHP.

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


5
Questa non è in realtà una risposta tanto quanto un collegamento a una pagina Web con una potenziale risposta.
faintsignal

-1

Se intendi il metodo di concatenamento come in JavaScript (o alcune persone tengono a mente jQuery), perché non prendere semplicemente una libreria che porta quel dev. esperienza in PHP? Ad esempio Extra - https://dsheiko.github.io/extras/ Questo estende i tipi di PHP con i metodi JavaScript e Underscore e fornisce il concatenamento:

È possibile concatenare un tipo particolare:

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

o

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

In alternativa puoi andare polimorfico:

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

Questo in realtà non risponde alla domanda ("Che cos'è il concatenamento di metodi?"). Anche la domanda originale ha 8 anni e ha già ricevuto una serie di risposte migliori
GordonM,

-1

Di seguito è riportato il mio modello che è in grado di trovare per ID nel database. Il metodo with ($ data) è il mio parametro aggiuntivo per la relazione, quindi restituisco $ this che è l'oggetto stesso. Sul mio controller sono in grado di incatenarlo.

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

puoi spiegare cosa fa questo?
ichimaru,

qualche spiegazione di cosa si tratta?
Patrick,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.