PHP chaînage de méthode?

J'utilise PHP 5 et j'ai entendu parler d'une nouvelle caractéristique de l'approche orientée objet, appelée 'method chaining'. C'est quoi exactement? Comment puis-je mettre en œuvre?

138
demandé sur aalaap 2010-09-16 10:04:37

8 réponses

assez simple, vraiment, vous avez une série de mutateur " méthodes que tous les retours de l'original (ou autres) des objets, 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();

Ce sorties "ab"

essayez en ligne!

283
répondu Kristoffer Sall-Storgaard 2018-06-07 10:52:27

en gros, vous prenez un objet:

$obj = new ObjectWithChainableMethods();

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

$obj->doSomething();

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

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

c'est ça, vraiment. Deux choses importantes:

  1. comme vous le constatez, C'est PHP 5 seulement. 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 briserait votre code.

  2. encore une fois, vous devez retourner l'objet dans vos méthodes de chaîne:

    public function doSomething() {
        // Do stuff
        return $this;
    }
    
    public function doSomethingElse() {
        // Do more stuff
        return $this;
    }
    
40
répondu BoltClock 2010-09-16 06:12:53

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'

?>
16
répondu mwangaben 2017-02-21 02:06:43

chaînage de Méthode signifie que vous pouvez enchaîner les appels de méthode:

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

cela signifie que la méthode1() doit retourner un objet et que la méthode2() donne le résultat de la méthode1(). La Method2 () transmet ensuite la valeur de retour à la method3 ().

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

9
répondu alexn 2013-08-13 02:12:42

il y a 49 lignes de code qui vous permet d'enchaîner des méthodes sur des tableaux comme celui-ci:

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

voir cet article qui vous montre comment enchaîner toutes les 70 fonctions array_ de PHP.

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

5
répondu Lukas Dong 2017-02-27 10:47:43

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();
5
répondu Rashedul Islam Sagor 2017-04-04 09:57:06
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);
    }
}
0
répondu bryan rivera 2017-02-02 06:02:11

si vous voulez dire enchaînement de méthode comme dans JavaScript (ou certaines personnes gardent à l'esprit jQuery), pourquoi ne pas simplement prendre une bibliothèque qui apporte ce dev. expérience en PHP? Par exemple Extras - https://dsheiko.github.io/extras / celui-ci étend les types PHP avec les méthodes JavaScript et Underscore et fournit le chaînage:

vous pouvez enchaîner un type particulier:

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

ou

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

alternativement vous pouvez devenir polymorphe:

<?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"
-1
répondu Dmitry Sheiko 2018-04-12 09:13:08