Вопрос:

PHP последний объект цепочки методов

php oop methods chaining method-chaining

712 просмотра

4 ответа

6786 Репутация автора

В PHP с использованием цепочки методов, как можно было бы обеспечить функциональный вызов после последнего метода, вызываемого в цепочке?

Также при использовании того же экземпляра (см. Ниже). Это убило бы идею реализации деструктора.

Конечным результатом является возвращаемое значение и функциональный вызов private "insert ()" из определенных свойств цепочки (разумеется) без необходимости вызывать его публично, независимо от порядка.

Обратите внимание, что если я вызову эхо (__toString) методов вместе, то получит окончательно сгенерированный уникальный код, который является нормальным поведением приведения строки.

Пример ниже:

class object
{
    private $data;
    function __construct($name) {
        // ... some other code stuff
    }

    private function fc($num) {
        // some wicked code here
    }

    public function green($num) {
        $this->data .= fc($num*10);
        return $this;
    }
    public function red($num) {
        $this->data .= fc($num*25);
        return $this;
    }
    public function blue($num) {
        $this->data .= fc($num*1);
        return $this;
    }

    // how to get this baby to fire ?
   private function insert() {
          // inserting
          file_put_content('test_code.txt', $this->data);
   }
}

$tss = new object('index_elements');

$tss->blue(100)->green(200)->red(100);       // chain 1
$tss->green(0)->red(100)->blue(0);           // chain 2
$tss->blue(10)->red(80)->blue(10)->green(0); // chain 3

Цепочки 1 , 2 и 3 будут генерировать уникальный код, содержащий все значения из методов и предоставляющий действие, например, автоматическую вставку в БД или создание файла (используется в этом примере).

Как вы можете видеть, нет настройки строки или произнесение или эхо.

Автор: tfont Источник Размещён: 17.04.2014 05:01

Ответы (4)


1 плюс

56 Репутация автора

Я с PeeHaa, это не имеет смысла! :)

Единственный шанс, что что-то волшебным образом произойдет после того, как была использована последняя цепочка (без возможности заглядывать в будущее), это функция Destructor / Shutdown ИЛИ ручное приведение / вызов insert ()

Автор: LJay Размещён: 17.04.2014 05:15

3 плюса

1260 Репутация автора

Решение

Вы можете сохранить список вещей, которые должны быть инициализированы, и были ли они таковыми в этом случае или нет. Затем проверяйте список каждый раз, когда вы используете один из методов инициализации. Что-то вроде:

class O {
    private $init = array
        ( 'red' => false
        , 'green' => false
        , 'blue' => false
        );

    private function isInit() {
        $fin = true;
        foreach($this->init as $in) {
            $fin = $fin && $in;
        }
        return $fin;
    }

    public function green($n) {
        $this->init['green'] = true;
        if($this->isInit()) {
            $this->insert();
        }
    }

    public function red($n) {
        $this->init['red'] = true;
        if($this->isInit()) {
            $this->insert();
        }
    }

    public function blue($n) {
        $this->init['blue'] = true;
        if($this->isInit()) {
            $this->insert();
        }
    }

    private function insert() {
        echo "whee\n";
    }
}

Но лично я думаю, что это будет больше хлопот, чем стоит. Лучше imo представить ваш insertметод и позволить пользователю вашего кода сказать, когда инициализация завершена. Так что то, что должно быть использовано, как:

$o->red(1)->green(2)->blue(0)->insert();

-Обновить-

Если это так, что невозможно предсказать, какие функции нужно вызывать, вам действительно нужно четко об этом сказать. Я не вижу способа обойти это. Причина в том, что php действительно не может отличить

$o1 = new A();
$o2 = $o1->stuff();

а также

$o2 = (new A())->stuff();

На языке, который допускает перегрузку, =я думаю, это было бы возможно, но на самом деле очень запутанно и, как правило, не очень хорошая идея.

Можно переместить явную часть так, чтобы она не находилась в конце цепочки вызовов, но я не уверен, сделает ли это вас счастливее? Это также пошло бы против вашего желания не использовать другой экземпляр. Это может выглядеть примерно так:

class O {
    public function __construct(InitO $ini) {
        // Do stuff
        echo "Whee\n";
    }
}

class InitO {
    public function red($n) {
        return $this;
    }
    public function green($n) {
        return $this;
    }
    public function blue($n) {
        return $this;
    }
}

$o = new O((new InitO())->red(10)->red(9)->green(7));

Конечно, вы можете использовать только один экземпляр, используя другой способ обертывания, но единственные способы, о которых я могу подумать сейчас, будут выглядеть намного ужаснее.

Автор: monocell Размещён: 17.04.2014 05:18

0 плюса

14 Репутация автора

Вы также можете решить реализовать это статически, не используя объекты.

<?php
class Object
{
    private static $data;

    public static function set($name) 
    {
        // ... some other code stuff
    }

    private static function fc($num) 
    {
        // some wicked code here
    }

    public static function green($num) 
    {
        self::$data .= self::fc($num*10);
        return new static;
    }

    public static function red($num) 
    {
        self::$data .= self::fc($num*25);
        return new static;
    }

    public static function blue($num) {
        self::$data .= self::fc($num*1);
        return new static;
    }

    // how to get this baby to fire ?
    public static function insert() 
    {
       // inserting
       file_put_content('test_code.txt', self::$data);
    }

}

//$tss = new object('index_elements');

    $Object::set('index_elements')->blue(100)->green(200)->red(100)->insert();       // chain 1
    $Object::set('index_elements')->green(0)->red(100)->blue(0)->insert();           // chain 2
    $Object::set('index_elements')->blue(10)->red(80)->blue(10)->green(0)->insert(); // chain 3

?>
Автор: geoffreybans Размещён: 04.01.2016 07:21

0 плюса

251 Репутация автора

Хорошо, давайте посмотрим пример кода

<?php

// map dummy class
class map
{
// __call magic method
public function __call($name, $args)
{
return $this;
}
}

// now we chain
$map = new map;

// let's find me

$map->start('here')
->go('right')
->then()
->turn('left')
->and('get water')
->dontEat()
->keep('going')
->youShouldSeeMe('smiling');

здесь мы не знаем, каким был бы последний метод, и нам нужно запустить своего рода операцию или событие, как только мы достигнем конца.

В соответствии со структурой данных мы можем назвать это стеком LIFO. (Последний пришел первым вышел)

так как я решил это на PHP?

// я сделал некоторую обратную трассировку

... вернуться к функции __call

function __call($name, $args)
{

$trace = debug_backtrace()[0];
$line = $trace['line'];
$file = $trace['file'];
$trace = null;
$getFile = file($file);
$file = null;
$getLine = trim($getFile[$line-1]);
$line = null;
$getFile = null;

$split = preg_split("/(->)($name)/", $getLine);
$getLine = null;

if (!preg_match('/[)](->)(\S)/', $split[1]) && preg_match('/[;]$/', $split[1]))
{
// last method called.
var_dump($name); // outputs: youShouldSeeMe
}

$split = null;

return $this;
}

И чёрт возьми, мы можем позвонить как угодно, как только достигнем дна. * (Обратите внимание, что я использую null, как только я закончу с переменной, я из семейства C, где мы сами управляем памятью)

Надеюсь, это поможет вам так или иначе.

Автор: Ifeanyi Amadi Размещён: 14.04.2019 11:07
Вопросы из категории :
32x32