PHP 메소드 체인?


170

PHP 5를 사용하고 있으며 'method chaining'이라는 객체 지향 접근 방식의 새로운 기능에 대해 들었습니다. 정확히 무엇입니까? 어떻게 구현합니까?


1
모든 질문이 체인과 관련된 기술에 관한 것이 아니라면, 가장 구체적으로 말하면 달성 방법에 관한 것입니다.
Kristoffer Sall-Storgaard

@Kristoffer OP는 이러한 질문에서 어떻게 달성되는지 쉽게 알 수있었습니다.
Gordon

2
@Kristoffer 또한 Google 에서 메소드 체인 PHP를 검색 하면 Salathe 의 첫 번째 자습서 로 OP에 자습서 를 제공했을 것 입니다. 쉬운 질문에 대답하는 것은 좋지 않지만 일부 사람들은 너무 게으르다.
Gordon

6
저는 여러분의
퍼포먼스

답변:


333

오히려 간단 합니다. 모두 원래 (또는 다른) 객체를 반환 하는 일련의 mutator 메소드 가 있으므로 반환 된 객체에서 메소드를 계속 호출 할 수 있습니다.

<?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
이것은 또한 때때로 유창함 인터페이스라고
Nithesh 찬드라에게

17
@Nitesh가 잘못되었습니다. Fluent InterfacesMethod Chaining 을 기본 메커니즘으로 사용하지만 동일하지는 않습니다 . Fluent Interface는 DSL 생성을 목표로하는 반면 메소드 체인은 단순히 호스트 객체를 반환합니다 . 예 : $foo->setBar(1)->setBaz(2)$table->select()->from('foo')->where('bar = 1')->order('ASC). 후자는 여러 객체에 걸쳐 있습니다.
Gordon

3
공용 함수 __toString () {return $ this-> str; } 체인을 이미 반향하는 경우 마지막 메소드 "getStr ()"이 필요하지 않습니다.
tfont

6
@tfont True, 그러나 우리는 마법의 방법을 소개합니다. 한 번에 하나의 개념으로 충분합니다.
Kristoffer Sall-Storgaard

3
PHP 5.4부터는 한 줄로 모든 것이 가능합니다 :$a = (new fakeString())->addA()->addB()->getStr();
Philzen

48

기본적으로 객체를 가져옵니다.

$obj = new ObjectWithChainableMethods();

return $this;마지막에 효과적으로 수행하는 메소드를 호출하십시오 .

$obj->doSomething();

동일한 객체 또는 동일한 객체에 대한 참조 를 반환하므로 다음과 같이 동일한 클래스의 메서드를 반환 값에서 계속 호출 할 수 있습니다.

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

그게 다야. 중요한 두 가지 :

  1. 아시다시피, 그것은 PHP 5 전용입니다. PHP 4에서는 값으로 객체를 반환하므로 객체의 다른 사본에서 메소드를 호출하여 코드를 손상시킬 수 있기 때문에 제대로 작동하지 않습니다.

  2. 다시 말하지만, 연결 가능한 메소드에서 객체를 반환해야합니다.

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

return &$thisPHP4에서 할 수 있습니까?
alex

@ alex : 지금 테스트 할 PHP 4가 없지만 확실하지 않습니다.
BoltClock

4
나도 그렇게 생각하지 않았지만 제대로 작동 해야 합니까? PHP4가 PHP4가 아니었을 수도 있습니다.
alex

당신의 방법 체인의 전체 간단한 단계를 얻을 수 있습니다 techflirt.com/tutorials/oop-in-php/php-method-chaining.html
Ankur 쿠마르 싱에게

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

체인에서 첫 번째 요소와 마지막 요소 (호출)를 식별하는 방법 때때로 이것은 이제 순서대로 실행될 작업 목록 일 뿐이지 만 모든 요소를 ​​수집 한 후에 수행해야하는 작업입니다. 여기에서 SQL 쿼리를 실행하는 것과 마찬가지로 하나의 객체에서 여러 체인 호출을 수행 할 수 있습니다! 굳고 마지막.
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 글쎄, 호스트 객체는 반환되지 않는다. 모든 객체를 반환하고 연결할 수 있습니다.
alexn

2
그런 다음 Fowler에서 정의한대로 메소드 체인이 아니라고 주장합니다. 예를 들어 수정 자 메소드는 단일 표현식에서 여러 수정자를 호출 할 수 있도록 호스트 오브젝트를 리턴합니다. -다른 객체를 반환하면 Fluent Interface 일 가능성이 높습니다. :
Gordon

와우, 나는 거의 8 살짜리 게시물에 대해 언급하고 있음을 알고 있습니다. 그러나 당신이 가지고있는 귀하의 링크는 다른 웹 사이트로 리디렉션됩니다. 그냥 피
willbeeler

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
이것은 실제로 잠재적 인 답변이있는 웹 페이지에 대한 링크만큼의 답변은 아닙니다.
faintsignal

-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 2018 년

이것이 무엇을 설명합니까?
Patrick
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.