57

我想知道是否有办法在 PHP 中新创建的对象上链接方法?

就像是:

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

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

任何人都知道实现这一目标的方法吗?

4

7 回答 7

104

在 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 的调用,您可以使用方法调用实例化一个类,然后您就可以自由地将其链接起来。

于 2010-02-02T23:57:16.167 回答
23

像这样定义一个全局函数:

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

然后,您将可以致电:

with(new Foo)->xyz();
于 2011-07-12T18:32:15.230 回答
11

在 PHP 5.4 中,您可以链接一个新实例化的对象:

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

对于旧版本的 PHP,您可以使用 Alan Storm 的解决方案。

于 2012-06-10T16:42:35.710 回答
6

这个答案已经过时 - 因此想要更正它。

在 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

于 2013-10-26T22:40:18.753 回答
3

好吧,这可能是一个老问题,但就像编程中的很多事情一样——最终答案会改变。

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

希望这可以帮助像我一样遇到问题的人!

于 2013-04-30T09:23:57.750 回答
1

如果他们在未来的版本中“解决这个问题”,那将非常有帮助。我真的很欣赏链接的能力(尤其是在填充集合时):

我在我的框架的基类中添加了一个名为 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);

于 2011-02-14T05:43:26.030 回答
0

只是为了完整性(并且为了它的乐趣......),因为似乎没有人提到使用最短(和最不复杂)代码的解决方案。

对于经常使用的短期对象,特别是在编写测​​试用例时,您通常会创建大量对象,您可能希望优化打字方便(而不是纯度),并结合 Alan Storm 的Foo::instantiate()工厂方法和 Kenaniah 的with()全局函数技术.

只需将工厂方法设为与类同名的全局函数!. ;-o (要么将其添加为适当的静态的方便包装,要么Foo::instantiate()在没人看的时候将其移到那里。)

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

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

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

笔记:

  • 我不会在生产代码上这样做。虽然有点性感,但这是对基本编码原则的滥用(比如“最小意外原则”(尽管这实际上是相当直观的语法),或者“不要重复自己”,尤其是如果用一些包装真正的工厂方法参数,顺便说一句,它本身已经是对 DRY 的滥用......),再加上 PHP 将来可能会改变以以有趣的方式破坏这样的代码。
于 2015-07-23T23:21:06.053 回答