source

PHP 메서드 체인 또는 유창한 인터페이스

gigabyte 2022. 9. 6. 22:20
반응형

PHP 메서드 체인 또는 유창한 인터페이스

저는 PHP 5를 사용하고 있는데, '메서드 체인'이라는 객체 지향 접근법에 새로운 기능이 있다고 들었습니다.그것은 정확히 무엇이니?어떻게 구현해야 합니까?

그건 꽤 간단해, 정말.모두 원래(또는 다른) 개체를 반환하는 일련의 변환 메서드가 있습니다.이렇게 하면 반환된 오브젝트에서 호출 메서드를 계속 사용할 수 있습니다.

<?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"입니다.

온라인으로 시험해 보세요!

기본적으로 다음과 같은 오브젝트를 취합니다.

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

다음 코드를 사용해 보십시오.

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

?>

정적 메서드 체인의 다른 방법:

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

메서드 체인은 메서드콜을 체인할 수 있는 것을 의미합니다.

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

즉, method1()은 객체를 반환해야 하며 method2()는 method1()의 결과를 받습니다.Method2()는 반환값을 Method3()로 전달합니다.

좋은 기사: http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html

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

유창한 인터페이스를 사용하면 메서드콜을 체인할 수 있기 때문에, 같은 오브젝트에 복수의 조작을 적용했을 때에 입력되는 문자가 적어집니다.

class Bill { 

    public $dinner    = 20;

    public $desserts  = 5;

    public $bill;

    public function dinner( $person ) {
        $this->bill += $this->dinner * $person;
        return $this;
    }
    public function dessert( $person ) {
        $this->bill += $this->desserts * $person;
        return $this;
    }
}

$bill = new Bill();

echo $bill->dinner( 2 )->dessert( 3 )->bill;

이게 가장 적절한 대답인 것 같아요.

<?php

class Calculator
{
  protected $result = 0;

  public function sum($num)
  {
    $this->result += $num;
    return $this;
  }

  public function sub($num)
  {
    $this->result -= $num;
    return $this;
  }

  public function result()
  {
    return $this->result;
  }
}

$calculator = new Calculator;
echo $calculator->sum(10)->sub(5)->sum(3)->result(); // 8

JavaScript(또는 jQuery)와 같은 메서드 체인(method chaining)을 의미한다면 PHP에서 개발 경험을 제공하는 라이브러리를 이용하는 것은 어떨까요?예를 들어 Extra - 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"

아래는 데이터베이스에서 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);
    }
}

언급URL : https://stackoverflow.com/questions/3724112/php-method-chaining-or-fluent-interface

반응형