Как связать метод на вновь созданном объекте? - PullRequest
54 голосов
/ 03 февраля 2010

Я хотел бы знать, есть ли способ цепочки методов для вновь созданного объекта в PHP?

Что-то вроде:

class Foo {
    public function xyz() { ... return $this; }
}

$my_foo = new Foo()->xyz();

Кто-нибудь знает способ достижения этого?

Ответы [ 7 ]

98 голосов
/ 03 февраля 2010

В PHP 5.4+ парсер был изменен, поэтому вы можете сделать что-то вроде этого

(new Foo())->xyz();

Заверните экземпляр в круглые скобки и уберите цепочку.

До PHP 5.4, когда вы используете

new Classname();
Синтаксис

, вы не можете связать вызов метода от экземпляра. Это ограничение синтаксиса PHP 5.3. Как только объект создан, вы можете зацепиться за него.

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

class Foo
{
    public function xyz()
    {
        echo "Called","\n";
        return $this;
    }

    static public function instantiate()
    {
        return new self();
    }
}


$a = Foo::instantiate()->xyz();

Оборачивая вызов new в статический метод, вы можете создать экземпляр класса с помощью вызова метода, и тогда вы можете свободно связать это.

23 голосов
/ 12 июля 2011

Определите глобальную функцию следующим образом:

function with($object){ return $object; }

После этого вы сможете звонить:

with(new Foo)->xyz();
11 голосов
/ 10 июня 2012

В PHP 5.4 вы можете связать недавно созданный объект:

http://docs.php.net/manual/en/migration54.new-features.php

Для более старых версий PHP вы можете использовать решение Alan Storm.

6 голосов
/ 27 октября 2013

Этот ответ устарел - поэтому хотите его исправить.

В PHP 5.4.x вы можете связать метод с новым вызовом. Давайте возьмем этот класс в качестве примера:

<?php class a {
    public function __construct() { echo "Constructed\n"; }
    public function foo() { echo "Foobar'd!\n"; }
}

Теперь мы можем использовать это: $b = (new a())->foo();

И вывод:

Constructed
Foobar'd!

Дополнительную информацию можно найти в руководстве: http://www.php.net/manual/en/migration54.new-features.php

3 голосов
/ 30 апреля 2013

Ну, это может быть старый вопрос, но, как и во многих других вещах в программировании, в конце концов ответ меняется.

Что касается PHP 5.3, нет, вы не можете напрямую связываться с конструктором. Однако, чтобы расширить принятый ответ, чтобы должным образом приспособиться к наследованию, вы можете сделать:

abstract class Foo 
{    
    public static function create() 
    {
        return new static;
    }
}

class Bar extends Foo
{
    public function chain1()
    {
        return $this;
    }

    public function chain2()
    {
        return $this;
    }
}

$bar = Bar::create()->chain1()->chain2();

Это будет отлично работать и вернет вам новый экземпляр Bar ().

В PHP 5.4, однако, вы можете просто сделать:

$bar = (new Bar)->chain1()->chain2();

Надеюсь, это поможет кому-то наткнуться на вопрос, как у меня!

1 голос
/ 14 февраля 2011

Было бы очень полезно, если бы они исправили это в будущем выпуске. Я действительно ценю возможность цепочки (особенно при заполнении коллекций):

Я добавил метод к базовому классу моего фреймворка под названием create (), от которого можно связать цепочку. Должен работать со всеми классами-потомками автоматически.

class baseClass
{
    ...
    public final static function create()
    {
        $class = new \ReflectionClass(get_called_class());
        return $class->newInstance(func_get_args());
    }
    ...
    public function __call($method, $args)
    {
        $matches = array();
        if (preg_match('/^(?:Add|Set)(?<prop>.+)/', $method, $matches) > 0)
        {
            //  Magic chaining method
            if (property_exists($this, $matches['prop']) && count($args) > 0)
            {
                $this->$matches['prop'] = $args[0];
                return $this;
            }
        }
    }
    ...
}

Класс :: Create () -> SetName ( 'Kris') -> SetAge (36);

0 голосов
/ 24 июля 2015

Просто ради полноты (и ради удовольствия ...), поскольку никто, кажется, не упомянул решение с самым коротким (и наименее сложным) кодом.

Для часто используемых недолговечных объектов, особенно при написании тестовых случаев, где вы обычно создаете много объектов, вы можете оптимизировать их для удобства ввода (а не для чистоты), и сортировка объединяет фабрику Alan Storm Foo::instantiate() метод и метод глобальной функции with() Кенании.

Просто сделайте фабричный метод глобальной функцией с тем же именем, что и класс! . ; -o (Либо добавьте его в качестве удобной обертки вокруг правильной статики Foo::instantiate(), либо просто переместите его туда, где никто не смотрит.)

class Foo
{
    public function xyz()
    {
        echo "Called","\n";
        return $this;
    }
}

function Foo()
{
    return new Foo();
}

$a = Foo()->xyz();

Примечание:

  • Я НЕ БУДУ ЭТОГО СДЕЛАТЬ на производственный код. Хотя это и выглядит «сексуально», это является нарушением основных принципов кодирования (таких как «принцип наименьшего удивления» (хотя на самом деле это довольно интуитивно понятный синтаксис) или «не повторяйте себя», особенно если оборачивать настоящий фабричный метод некоторыми параметры, что само по себе, кстати, уже является злоупотреблением СУХОЙ ...), плюс PHP может измениться в будущем, чтобы забавным образом нарушать подобный код.
...