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

时间:2021-12-08 15:11:35

I would like to know whether there's a way to chain methods on a newly created object in PHP?

我想知道是否有一种方法可以链接PHP中新创建的对象上的方法?

Something like:

喜欢的东西:

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

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

Anyone know of a way to achieve this?

有人知道实现这个目标的方法吗?

7 个解决方案

#1


95  

In PHP 5.4+, the parser's been modified so you can do something like this

在PHP 5.4+中,解析器被修改了,所以您可以这样做

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

Wrap the instantiation in parenthesis, and chain away.

将实例化封装在括号中,并将其链化。

Prior to PHP 5.4, when you're using the

在使用PHP 5.4之前

new Classname();

syntax, you can't chain a method call off the instantiation. It's a limitation of PHP 5.3's syntax. Once an object is instantiated, you can chain away.

语法,您不能将一个方法挂起,取消实例化。这是PHP 5.3语法的一个限制。一旦实例化了一个对象,就可以将其链化。

One method I've seen used to get around this is a static instantiation method of some kind.

我所见过的一种方法就是使用某种静态实例化方法来解决这个问题。

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

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


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

By wrapping the call to new in a static method, you can instantiate a class with method call, and you're then free to chain off that.

通过在静态方法中包装对new的调用,您可以用方法调用实例化一个类,然后您可以*地将其链结起来。

#2


23  

Define a global function like this:

定义这样的全局函数:

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

You will then be able to call:

然后你就可以打电话:

with(new Foo)->xyz();

#3


11  

In PHP 5.4 you can chain off a newly instantiated object:

在PHP 5.4中,可以将一个新实例化的对象链起来:

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

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

For older versions of PHP, you can use Alan Storm's solution.

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

#4


5  

This answer is outdated - therefore want to correct it.

这个答案已经过时了——所以想要改正它。

In PHP 5.4.x you can chain a method to a new-call. Let's take this class as example:

在PHP 5.4。可以将一个方法链接到一个新调用。我们以这门课为例:

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

Now, we can use this: $b = (new a())->foo();

现在,我们可以使用这个:$b = (new a())->foo();

And the output is:

和输出是:

Constructed
Foobar'd!

Further information may be found on the manual: http://www.php.net/manual/en/migration54.new-features.php

进一步的信息可以在手册中找到:http://www.php.net/manual/en/migration54.new-features.php

#5


2  

Well, this may be an old question but as with a lot of things in programming - eventually the answer changes.

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

Regarding PHP 5.3, no, you can't chain directly from the constructor. To expand on the accepted answer however, in order to properly accommodate for inheritance, you can do:

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

That will work just fine and will return you a new Bar() instance.

这将很好地工作,并将返回一个新的Bar()实例。

In PHP 5.4, however, you can simply do:

但是,在PHP 5.4中,您只需:

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

Hopefully this helps someone stumbling across the question like I have!

希望这能帮助像我这样的人遇到这个问题!

#6


1  

It would be really helpful if they 'fix this' in a future release. I really appreciate the ability to chain (especially when populating collections):

如果他们在未来的版本中“修复”这个问题,那将会非常有帮助。我真的很欣赏这种能力(尤其是在推广收藏时):

I added a method to the base class of my framework called create() that can be chained off of. Should work with all descendant classes automatically.

我将一个方法添加到我的框架的基类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('Kris')->SetAge(36);

Class::create()- > SetName(克里斯)- > SetAge(36);

#7


0  

Just for the sake of completeness (and for the fun of it...), since nobody seems to have mentioned the solution with the shortest (and least sophisticated) code.

只是为了完整性(也为了有趣…),因为似乎没有人提到过使用最短(也是最不复杂)代码的解决方案。

For frequently used short-lived objects, especially when writing test cases, where you typically do lots of object creation, you may want to optimize for typing convenience (rather than purity), and sorta' combine Alan Storm's Foo::instantiate() factory method and Kenaniah's with() global function technique.

对于经常使用的短期对象,特别是在编写测试用例时,通常要进行大量的对象创建,您可能想要优化输入方便(而不是纯粹),而sorta'结合了Alan Storm的Foo:::instantiate() factory方法和Kenaniah的()全局函数技术。

Simply make the factory method a global function with the same name as the class!. ;-o (Either add it as a convenience wrapper around the proper static Foo::instantiate() or just move it out there while nobody is looking.)

只需使factory方法成为与类同名的全局函数!-o(或者将它作为合适的静态Foo::实例化()的便利包装,或者在没有人注意的时候将它移到那里)。

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

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

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

NOTE:

注意:

  • I WOULDN'T DO THIS on production code. While kinda' sexy, this is an abuse on basic coding principles (like "principle of least surprise" (although this is actually rather intuitive syntax), or "don't repeat yourself", esp. if wrapping a real factory method with some parameters, which itself, BTW, is already an abuse of DRY...), plus PHP may change in he future to break code like this in funny ways.
  • 我不会在生产代码上这么做。虽然有点性感,这是基本的编码原则的滥用(如“最小惊讶原则”(尽管这其实是相当直观的语法),或“不要重复自己”,特别是如果包装一个真正的工厂方法和一些参数,这本身,顺便说一句,已经是滥用干…),+ PHP在他将来可能会改变以有趣的方式打破这样的代码。

#1


95  

In PHP 5.4+, the parser's been modified so you can do something like this

在PHP 5.4+中,解析器被修改了,所以您可以这样做

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

Wrap the instantiation in parenthesis, and chain away.

将实例化封装在括号中,并将其链化。

Prior to PHP 5.4, when you're using the

在使用PHP 5.4之前

new Classname();

syntax, you can't chain a method call off the instantiation. It's a limitation of PHP 5.3's syntax. Once an object is instantiated, you can chain away.

语法,您不能将一个方法挂起,取消实例化。这是PHP 5.3语法的一个限制。一旦实例化了一个对象,就可以将其链化。

One method I've seen used to get around this is a static instantiation method of some kind.

我所见过的一种方法就是使用某种静态实例化方法来解决这个问题。

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

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


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

By wrapping the call to new in a static method, you can instantiate a class with method call, and you're then free to chain off that.

通过在静态方法中包装对new的调用,您可以用方法调用实例化一个类,然后您可以*地将其链结起来。

#2


23  

Define a global function like this:

定义这样的全局函数:

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

You will then be able to call:

然后你就可以打电话:

with(new Foo)->xyz();

#3


11  

In PHP 5.4 you can chain off a newly instantiated object:

在PHP 5.4中,可以将一个新实例化的对象链起来:

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

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

For older versions of PHP, you can use Alan Storm's solution.

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

#4


5  

This answer is outdated - therefore want to correct it.

这个答案已经过时了——所以想要改正它。

In PHP 5.4.x you can chain a method to a new-call. Let's take this class as example:

在PHP 5.4。可以将一个方法链接到一个新调用。我们以这门课为例:

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

Now, we can use this: $b = (new a())->foo();

现在,我们可以使用这个:$b = (new a())->foo();

And the output is:

和输出是:

Constructed
Foobar'd!

Further information may be found on the manual: http://www.php.net/manual/en/migration54.new-features.php

进一步的信息可以在手册中找到:http://www.php.net/manual/en/migration54.new-features.php

#5


2  

Well, this may be an old question but as with a lot of things in programming - eventually the answer changes.

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

Regarding PHP 5.3, no, you can't chain directly from the constructor. To expand on the accepted answer however, in order to properly accommodate for inheritance, you can do:

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

That will work just fine and will return you a new Bar() instance.

这将很好地工作,并将返回一个新的Bar()实例。

In PHP 5.4, however, you can simply do:

但是,在PHP 5.4中,您只需:

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

Hopefully this helps someone stumbling across the question like I have!

希望这能帮助像我这样的人遇到这个问题!

#6


1  

It would be really helpful if they 'fix this' in a future release. I really appreciate the ability to chain (especially when populating collections):

如果他们在未来的版本中“修复”这个问题,那将会非常有帮助。我真的很欣赏这种能力(尤其是在推广收藏时):

I added a method to the base class of my framework called create() that can be chained off of. Should work with all descendant classes automatically.

我将一个方法添加到我的框架的基类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('Kris')->SetAge(36);

Class::create()- > SetName(克里斯)- > SetAge(36);

#7


0  

Just for the sake of completeness (and for the fun of it...), since nobody seems to have mentioned the solution with the shortest (and least sophisticated) code.

只是为了完整性(也为了有趣…),因为似乎没有人提到过使用最短(也是最不复杂)代码的解决方案。

For frequently used short-lived objects, especially when writing test cases, where you typically do lots of object creation, you may want to optimize for typing convenience (rather than purity), and sorta' combine Alan Storm's Foo::instantiate() factory method and Kenaniah's with() global function technique.

对于经常使用的短期对象,特别是在编写测试用例时,通常要进行大量的对象创建,您可能想要优化输入方便(而不是纯粹),而sorta'结合了Alan Storm的Foo:::instantiate() factory方法和Kenaniah的()全局函数技术。

Simply make the factory method a global function with the same name as the class!. ;-o (Either add it as a convenience wrapper around the proper static Foo::instantiate() or just move it out there while nobody is looking.)

只需使factory方法成为与类同名的全局函数!-o(或者将它作为合适的静态Foo::实例化()的便利包装,或者在没有人注意的时候将它移到那里)。

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

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

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

NOTE:

注意:

  • I WOULDN'T DO THIS on production code. While kinda' sexy, this is an abuse on basic coding principles (like "principle of least surprise" (although this is actually rather intuitive syntax), or "don't repeat yourself", esp. if wrapping a real factory method with some parameters, which itself, BTW, is already an abuse of DRY...), plus PHP may change in he future to break code like this in funny ways.
  • 我不会在生产代码上这么做。虽然有点性感,这是基本的编码原则的滥用(如“最小惊讶原则”(尽管这其实是相当直观的语法),或“不要重复自己”,特别是如果包装一个真正的工厂方法和一些参数,这本身,顺便说一句,已经是滥用干…),+ PHP在他将来可能会改变以有趣的方式打破这样的代码。