190 votes

Enchaînement de méthodes PHP ou interface fluide ?

J'utilise PHP 5 et j'ai entendu parler d'une nouvelle fonctionnalité de l'approche orientée objet, appelée "chaînage de méthodes". Qu'est-ce que c'est exactement ? Comment puis-je l'implémenter ?

1 votes

Je dirais que la plupart de ces questions, si ce n'est toutes, portent sur les aspects techniques du chaînage, alors que celle-ci porte plus spécifiquement sur la manière de le réaliser.

0 votes

@Kristoffer le PO aurait pu facilement trouver comment il est réalisé à partir de ces questions.

2 votes

@Kristoffer en outre, la recherche de enchaînement de méthodes php sur Google aurait donné au PO une tutoriel par Salathe comme tout premier résultat. Ça ne me dérange pas de répondre à des questions faciles, mais certaines personnes sont simplement trop paresseuses.

367voto

Kristoffer S Hansen Points 4868

C'est assez simple, vraiment. Vous avez une série de méthodes du mutateur qui renvoient tous l'objet original (ou autre). De cette façon, vous pouvez continuer à appeler des méthodes sur l'objet retourné.

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

Cela donne "ab".

Essayez-le en ligne !

13 votes

On parle aussi parfois d'interface fluide.

20 votes

@Nitesh c'est incorrect. Interfaces fluides utiliser Chaînage de méthodes comme leur principal mécanisme, mais ce n'est pas la même chose . Le chaînage de méthodes renvoie simplement l'objet hôte, tandis qu'une interface fluide vise à créer un objet de type DSL . Ex : $foo->setBar(1)->setBaz(2) vs $table->select()->from('foo')->where('bar = 1')->order('ASC) . Ce dernier englobe plusieurs objets.

4 votes

Public function __toString() { return $this->string ; } La dernière méthode "getStr()" n'est pas nécessaire si la chaîne est déjà affichée.

50voto

BoltClock Points 249668

En gros, vous prenez un objet :

$obj = new ObjectWithChainableMethods();

Appelez une méthode qui fait effectivement un return $this; à la fin :

$obj->doSomething();

Puisqu'elle renvoie le même objet, ou plutôt, une référence au même objet, vous pouvez continuer à appeler des méthodes de la même classe à partir de la valeur de retour, comme ceci :

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

C'est tout, vraiment. Deux choses importantes :

  1. Comme vous l'avez noté, il s'agit de PHP 5 uniquement. Il ne fonctionnera pas correctement en PHP 4 car il renvoie des objets par valeur et cela signifie que vous appelez des méthodes sur différentes copies d'un objet, ce qui casserait votre code.

  2. Encore une fois, vous devez retourner l'objet dans vos méthodes chaînables :

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

0 votes

Pourriez-vous faire return &$this en PHP4 ?

0 votes

@alex : Je n'ai pas PHP 4 à tester pour le moment, mais je suis presque sûr que non.

4 votes

Je ne le pensais pas non plus, mais c'est devrait fonctionnent bien ? Peut-être que si PHP4 n'était pas aussi PHP4.

33voto

mwangaben Points 21

Essayez ce 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'

?>

16voto

Une autre façon d'enchaîner les méthodes statiques :

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

Appel à

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

echo "<br />";

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

13voto

alexn Points 25639

Le chaînage de méthodes signifie que vous pouvez enchaîner les appels de méthodes :

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

Cela signifie que la méthode1() doit retourner un objet, et que la méthode2() reçoit le résultat de la méthode1(). La méthode2() transmet ensuite la valeur de retour à la méthode3().

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

5 votes

L'explication est un peu fausse. Les valeurs de retour ne sont pas transmises. Les méthodes renvoient simplement l'objet hôte.

0 votes

Gordon Eh bien, l'objet hôte n'est pas retourné. N'importe quel objet peut être retourné et enchaîné.

2 votes

Dans ce cas, je dirais qu'il ne s'agit pas d'un enchaînement de méthodes tel que défini par Fowler, par ex. Faire en sorte que les méthodes de modification renvoient l'objet hôte afin que plusieurs modificateurs puissent être invoqués dans une seule expression. - si vous retournez d'autres objets, il s'agit plus probablement d'une interface fluide :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X