PHPメソッドの連鎖?


170

私はPHP 5を使用していますが、「メソッドチェーニング」と呼ばれるオブジェクト指向アプローチの新機能について聞いたことがあります。正確には何ですか?どうすれば実装できますか?


1
これらの質問のすべてがチェーンに関する技術に関するものではないにせよ、これは具体的にどのようにそれを達成するかに関するものだと思います。
Kristoffer Sall-Storgaard 2010

OPの@Kristofferは、これらの質問からOPがどのように達成されるかを簡単に見つけることができました。
ゴードン

2
@Kristofferに加えて、Googleメソッドチェーンのphpを検索すると、最初の結果としてOPにSalatheによるチュートリアル提供されます。簡単な質問に答えてもかまいませんが、怠惰すぎる人もいます。
Gordon

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

これは「ab」を出力します

オンラインでお試しください!


10
これは、Fluent Interfaceとも呼ばれます
Nithesh Chandra '16

17
不正解です。Fluentインターフェイスは、主要なメカニズムとしてメソッドチェーンを使用しますが、同じではありません。メソッドチェーンは単にホストオブジェクトを返しますが、FluentインターフェイスはDSLの作成を目的としています。例:$foo->setBar(1)->setBaz(2)$table->select()->from('foo')->where('bar = 1')->order('ASC)。後者は複数のオブジェクトにまたがります。
ゴードン

3
public function __toString(){return $ this-> str; すでにチェーンをエコーし​​ている場合、これは最後のメソッド「getStr()」を必要としません。
tfont 14

6
@tfont確かに、それでは魔法の方法を紹介します。一度に1つのコンセプトで十分です。
Kristoffer Sall-Storgaard 14

3
PHP 5.4以降では、することも可能ですすべて 1行で:$a = (new fakeString())->addA()->addB()->getStr();
Philzen

48

基本的に、オブジェクトを取得します。

$obj = new ObjectWithChainableMethods();

return $this;最後にaを効果的に実行するメソッドを呼び出します。

$obj->doSomething();

同じオブジェクト、または同じオブジェクトへの参照を返すため、次のように、戻り値から同じクラスのメソッドを引き続き呼び出すことができます。

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

それだけです。2つの重要なこと:

  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風ではなかったとしたら。
アレックス


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
これは私が良い説明と呼んでいるものです...チェーニング方法は常に私にグーズバムを与えます!!
MYNE 2016

チェーン内の最初と最後の要素(呼び出し)を(メソッド内で)識別する方法。時々、これは順番に実行される操作のリストにすぎないことがありますが、すべての要素を収集した後に実行する必要があるためです。ここでSQLクエリを実行するのと同じですが、1つのオブジェクトに対して複数の連鎖呼び出しを実行できることに注意してください。それぞれに最初と最後。
Andris

12

メソッドチェーンとは、メソッド呼び出しをチェーンできることを意味します。

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

つまり、method1()はオブジェクトを返す必要があり、method2()にはmethod1()の結果が与えられます。次に、Method2()は戻り値をmethod3()に渡します。

良い記事:http : //www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html


5
説明は少しずれています。戻り値は渡されません。メソッドは単にホストオブジェクトを返します。
Gordon

@Gordonまあ、ホストオブジェクトは返されません。任意のオブジェクトを返し、チェーンすることができます。
alexn

2
次に、Fowlerによって定義されたメソッドチェーンではないと主張します。たとえば、Makeモディファイアメソッドはホストオブジェクトを返すため、1つの式で複数のモディファイヤを呼び出すことができます。-他のオブジェクトを返す場合、それは流暢なインターフェイスである可能性が高いです:)
Gordon

うわー、私はほぼ8年前の投稿にコメントしていることを理解しています。しかし、あなたがそこに持っているあなたのリンクは、いくつかの他のウェブサイトにリダイレクトしています。ただファイ。
willbeeler '19年

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の70個のarray_関数をすべて連鎖させる方法を示すこの記事を参照してください。

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


5
これは実際には回答ではなく、回答の可能性があるWebページへのリンクです。
かすかな信号2016

-1

JavaScript(または一部の人々はjQueryを念頭に置いている)のようにメソッドチェーンを意味している場合は、その開発者をもたらすライブラリを取得しないでください。PHPでの経験?たとえば、Extras- https://dsheiko.github.io/extras/これは、JavaScriptおよびUnderscoreメソッドを使用して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歳で、すでに優れた回答の数を持っている
GordonM

-1

以下は、データベース内のIDで検索できる私のモデルです。with($ data)メソッドは関係の追加パラメーターなので、オブジェクト自体である$ thisを返します。私のコントローラーでは、それをチェーンすることができます。

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

これは何をするのですか?
ichimaru

これは何をするのですか?
Patrick
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.