Как связать метод с вновь созданным объектом?

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

Что-то типа:

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

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

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


person aefxx    schedule 02.02.2010    source источник


Ответы (7)


В 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 в статический метод, вы можете создать экземпляр класса с вызовом метода, и затем вы можете свободно связывать его.

person Alan Storm    schedule 02.02.2010
comment
+1 Да, я собирался ответить, используя фабричный метод, и это в основном то, что вы показываете. - person Bill Karwin; 03.02.2010
comment
Я предпочитаю не использовать жаргон ОО в ответе, когда спрашивающий не выглядит погруженным в культуру CS. Лучше они усвоят понятие, а потом идентифицируют его по имени собственному, чем испугаются новых терминов. - person Alan Storm; 03.02.2010
comment
-1 Это не решает проблему конструктора, кроме того, у вас будут проблемы с наследованием. - person Kenaniah; 12.07.2011
comment
Эм, да, это так? Проблема конструктора, о которой я говорил, заключалась в невозможности создания экземпляра объекта и немедленной цепочки, и да, есть компромиссы, связанные с наследованием и используемой версией PHP со статической привязкой. - person Alan Storm; 12.07.2011
comment
Если вы собираетесь использовать статический метод инстанцирования, вы должны заставить его вызывать new static вместо new self. Таким образом, если вы вызываете его для подкласса Foo, он создаст экземпляр подкласса, а не самого Foo. - person JW.; 15.12.2014

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

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

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

with(new Foo)->xyz();
person Kenaniah    schedule 12.07.2011
comment
Я лично предпочитаю этот ответ Алану, его можно легко реализовать в базовом классе фреймворка и, следовательно, решить проблему один раз, в одном месте, вместо того, чтобы реализовывать ответ Алана в каждом классе! Мне нравится СУХОЕ программирование!! - person Chris; 21.08.2012
comment
Это также называется идентификационной функцией, в некоторых библиотеках она обозначена как id(). Он широко используется в PHP благодаря своему синтаксису и парсеру. - person hakre; 01.01.2014
comment
Это было бы неплохо, но каким должен быть PHPDoc для этого метода? PHPStorm полагается на PHPDoc, чтобы сообщить ему, какие типы данных получает и возвращает функция; это не Java, поэтому дженерики недоступны. Я могу написать это как @param object $object + @return object, но тогда он не распознает правильный тип данных, и автодополнение/предложения не будут работать. - person jurchiks; 21.11.2014
comment
Действительно плохая идея загрязнять глобальное пространство имен пользовательской функцией имени with. Вы никогда не знаете, когда это станет зарезервированным ключевым словом или могут ли другие библиотеки использовать его. Так что используйте что-то уникальное вместо этого. - person TheStoryCoder; 30.05.2016

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

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

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

person Jackson    schedule 10.06.2012

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

В 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

person Ingwie Phoenix    schedule 26.10.2013
comment
Обратите внимание, что в вашем примере $b - это то, что возвращает foo(), а не (обязательно) созданный объект. - person artfulrobot; 28.01.2015
comment
@artfulrobot Я только понял, что тот, кто задавал вопрос, хотел только знать, как создать экземпляр и напрямую вызвать метод класса. Но ваше утверждение справедливо; вместо экземпляра класса возвращаемое значение foo(), которое в данном случае равно NULL, становится содержимым $b. - person Ingwie Phoenix; 28.01.2015

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

Что касается 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();

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

person Lukey    schedule 30.04.2013

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

Я добавил метод в базовый класс моего фреймворка с именем 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;
            }
        }
    }
    ...
}

Class::create()->SetName('Крис')->SetAge(36);

person Kris    schedule 14.02.2011
comment
-1 Это заставляет все классы наследовать от одного источника, кроме того, вам нужно было создать экземпляр ReflectionClass для достижения вашей цели. - person Kenaniah; 12.07.2011

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

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

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

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

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

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

ЗАМЕТКА:

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