如何在新创建的对象上链接方法?

时间:2010-02-02 23:45:37

标签: php constructor new-operator method-chaining

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

类似的东西:

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

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

任何人都知道如何实现这一目标?

7 个答案:

答案 0 :(得分:97)

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

答案 1 :(得分:23)

定义这样的全局函数:

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

然后您就可以致电:

with(new Foo)->xyz();

答案 2 :(得分:11)

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

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

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

答案 3 :(得分: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

答案 4 :(得分: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();

希望这有助于有人像我一样绊倒这个问题!

答案 5 :(得分: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;
            }
        }
    }
    ...
}

类::创建() - &GT; SETNAME( '克里斯') - &GT; SetAge(36);

答案 6 :(得分:0)

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

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

只需将工厂方法设为全局函数,其名称与类名相同! 。 ; -o(将其作为方便包装器添加到适当的静态with()周围,或者在没有人看的时候将其移出那里。)

Foo::instantiate()

注:

  • 我不会在生产代码上这样做。虽然有点性感,但这是对基本编码原则的滥用(比如“最少惊喜的原则”(虽然这实际上是相当直观的语法),或者“不要重复自己”,特别是如果用一些真正的工厂方法包装参数,其本身,BTW,已经滥用DRY ...),加上PHP可能会改变他未来以有趣的方式打破这样的代码。