PHP yöntem zincirleme?


170

PHP 5 kullanıyorum ve nesne yönelimli yaklaşımda 'yöntem zincirleme' adı verilen yeni bir özellik duydum. Tam olarak nedir? Nasıl uygularım?


1
Bu soruların tümü zincirleme ile ilgili teknikler değilse, daha çok bu konuya nasıl ulaşılacağı ile ilgili olduğunu söyleyebilirim.
Kristoffer Sall-Storgaard

@ Kristoffer OP bu sorulardan nasıl elde edildiğini kolayca bulabilirdi.
Gordon

2
@Kristoffer ek olarak, Google'da php yöntem zincirini aramak OP'ye Salathe tarafından ilk sonuç olarak bir öğretici verirdi . Kolay soruları cevaplamak sakıncası yok ama bazı insanlar çok tembel.
Gordon

Yanıtlar:


334

Oldukça basit, tüm orijinal (veya diğer) nesneleri döndüren bir dizi mutator yönteminiz var, bu şekilde döndürülen nesne üzerinde yöntemleri çağırmaya devam edebilirsiniz.

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

Bu "ab" çıktıları

Çevrimiçi deneyin!


11
Bu bazen Akıcı Arayüz olarak da adlandırılır
Nithesh Chandra

18
@Nitesh bu yanlış. Akıcı Arayüzler , birincil mekanizması olarak Yöntem Zinciri kullanır , ancak aynı değildir . Akıcı Arayüz bir DSL oluşturmayı amaçlarken, yöntem zincirleme sadece ana bilgisayar nesnesini döndürür . Ör: $foo->setBar(1)->setBaz(2)vs $table->select()->from('foo')->where('bar = 1')->order('ASC). İkincisi birden fazla nesneye yayılır.
Gordon

3
public function __toString () {return $ this-> str; } Zinciri zaten yankılanıyorsanız, son yöntem olan "getStr ()" yöntemini gerektirmez.
Nisan'da tfont

6
@tfont Doğru, ama sonra sihirli yöntemler sunuyoruz. Her seferinde bir konsept yeterli olmalıdır.
Kristoffer Sall-Storgaard

3
PHP 5.4'ten beri tek bir satırda her şey bile mümkün :$a = (new fakeString())->addA()->addB()->getStr();
Philzen

48

Temel olarak, bir nesne alırsınız:

$obj = new ObjectWithChainableMethods();

return $this;Sonunda etkili bir şekilde bir yöntem çağırabilirsiniz:

$obj->doSomething();

Aynı nesneyi veya daha ziyade aynı nesneye bir başvuru döndürdüğünden, aynı sınıfın yöntemlerini döndürülen değerden çağırmaya devam edebilirsiniz, şöyle:

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

Gerçekten bu kadar. İki önemli şey:

  1. Belirttiğiniz gibi, sadece PHP 5. PHP 4'te düzgün çalışmaz, çünkü nesneleri değere göre döndürür ve bu, bir nesnenin kodunu kıracak farklı kopyalarında yöntem çağırdığınız anlamına gelir.

  2. Yine, nesneyi zincirlenebilir yöntemlerinizde döndürmeniz gerekir:

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

return &$thisPHP4 ile yapabilir misiniz ?
alex

@alex: Şu anda test edilecek PHP 4'üm yok, ama emin değilim.
BoltClock

4
Öyle ya düşünmüyordu, ama gereken doğru çalışıyor? Belki PHP4 bu kadar PHP4-ish olmasaydı.
alex

Yöntem zincirlemesinin tüm basit adımlarını techflirt.com/tutorials/oop-in-php/php-method-chaining.html
Ankur Kumar Singh

28

Bu kodu deneyin:

<?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
Bu iyi bir açıklama diyorum ... zincirleme yöntemleri her zaman bana bektaşi üzümü verir!
MYNE

Zincirdeki ilk ve son elemanları (çağrıları) nasıl tanımlarım (yöntem içinde). Çünkü bazen bu sadece sırayla yürütülecek işlemlerin bir listesi, ancak tüm öğeleri topladıktan sonra yapılması gereken bir şey. Burada bir SQL sorgusu yürütmek gibi - ama bir nesne üzerinde birden fazla zincirleme çağrı yapabilirsiniz! Her birinde firt ve son.
Andris

12

Yöntem zinciri, yöntem çağrılarını zincirleyebileceğiniz anlamına gelir:

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

Bu, method1 () öğesinin bir nesneyi döndürmesi gerektiği ve method2 () yönteminin method1 () sonucunun verildiği anlamına gelir. Daha sonra Method2 (), return değerini method3 () öğesine iletir.

İyi makale: http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html


5
Açıklama biraz kapalı. Dönüş değerleri aktarılmaz. Yöntemler sadece host nesnesini döndürür.
Gordon

@Gordon Pekala, host nesnesi döndürülmez. Herhangi bir nesne iade edilebilir ve zincirlenebilir.
alexn

2
Daha sonra Fowler tarafından tanımlandığı gibi yöntem zincirleme olmadığını iddia ediyorum, örneğin, modifiye edici yöntemlerin ana nesneyi döndürmesini sağlayın, böylece birden fazla değiştirici tek bir ifadede çağrılabilir. - diğer nesneleri döndürürseniz, daha akıcı bir arayüz olabilir :)
Gordon

Vay canına, neredeyse 8 yaşında bir yazıya yorum yaptığımı anlıyorum .. Ama orada sahip olduğunuz bağ başka bir web sitesine yönlendiriyor. Sadece fyi.
willbeeler

11

Statik yöntem zincirlemesi için başka bir yol:

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

çağrı

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

echo "<br />";

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

6

Bu gibi diziler üzerinde yöntemleri zincirlemenizi sağlayan 49 kod satırı vardır:

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

Tüm PHP'nin yetmiş dizi_ işlevinin nasıl zincirleneceğini gösteren bu makaleye bakın.

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


5
Bu, potansiyel bir yanıtı olan bir web sayfasına bağlantı kadar bir cevap değildir.
faintsignal

-1

JavaScript'teki gibi zincirleme yöntemini kastediyorsanız (veya bazı insanlar jQuery'yi aklınızda tutarsanız), neden sadece bu geliştirmeyi getiren bir kütüphane almıyorsunuz? PHP deneyimi? Örneğin Ekstralar - https://dsheiko.github.io/extras/ Bu, PHP türlerini JavaScript ve Alt Çizgi yöntemleriyle genişletir ve zincirleme sağlar:

Belirli bir türü zincirleyebilirsiniz:

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

veya

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

Alternatif olarak polimorfik olabilir:

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

Bu gerçekten soruyu cevaplamıyor ("Yöntem zinciri nedir?"). Ayrıca orijinal soru 8 yaşında ve daha iyi cevapları var
GordonM

-1

Veritabanında kimliğe göre bulabilen modelim aşağıdadır. İle ($ data) yöntemi ilişki için benim ek parametreler olduğunu, bu yüzden nesnenin kendisi $ bu döndürür. Denetleyicimde zincir oluşturabiliyorum.

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

bunun ne yaptığını açıklayabilir misin?
2018'de

herhangi bir açıklama bu ne yapar?
Patrick
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.