How to chain method on a newly created object?

PhpConstructorNew OperatorMethod Chaining

Php Problem Overview


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

Something like:

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

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

Anyone know of a way to achieve this?

Php Solutions


Solution 1 - Php

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

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

Wrap the instantiation in parenthesis, and chain away.

Prior to PHP 5.4, when you're using the

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.

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.

Solution 2 - Php

Define a global function like this:

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

You will then be able to call:

with(new Foo)->xyz();

Solution 3 - Php

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

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

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

Solution 4 - Php

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 class a {
    public function __construct() { echo "Constructed\n"; }
    public function foo() { echo "Foobar'd!\n"; }
}

Now, we can use this: $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

Solution 5 - Php

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:

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.

In PHP 5.4, however, you can simply do:

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

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

Solution 6 - Php

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.

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);

Solution 7 - Php

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.

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.)

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionaefxxView Question on Stackoverflow
Solution 1 - PhpAlan StormView Answer on Stackoverflow
Solution 2 - PhpKenaniahView Answer on Stackoverflow
Solution 3 - PhpJacksonView Answer on Stackoverflow
Solution 4 - PhpIngwie PhoenixView Answer on Stackoverflow
Solution 5 - PhpLukeyView Answer on Stackoverflow
Solution 6 - PhpKrisView Answer on Stackoverflow
Solution 7 - PhpSz.View Answer on Stackoverflow