PHP 8.4 — new without parentheses for method chaining
Concept
PHP 8.4 introduced new without parentheses for method chaining. Before PHP 8.4, you couldn't chain methods directly on a new expression without wrapping it in parentheses: (new MyClass())->method(). PHP 8.4 allows new MyClass()->method() without the wrapping parentheses.
Why this matters: It's a quality-of-life improvement for fluent interfaces and method chaining. The extra parentheses around new expressions in chains were a visual tax that didn't add any semantic value.
Affected contexts: Works with new ClassName(), new ClassName, and new $variable(). Also works with property access (new Obj()->prop), array access (new Obj()['key']), and calling the object as a function (new Invokable()()).
Edge case — constructor args: The object's constructor arguments still require parentheses: new MyClass(1, 2)->method(). The change is that the second set of method-call parentheses no longer requires the whole new expression to be wrapped.
Impact on code style: Many developers already relied on this in static analysis (it was sometimes interpreted correctly) or used the parenthesis workaround. PHP 8.4 makes it official and consistent.
Code Example
<?php
declare(strict_types=1);
class StringBuilder
{
private string $str = '';
public function append(string $s): static
{
$this->str .= $s;
return $this;
}
public function prepend(string $s): static
{
$this->str = $s . $this->str;
return $this;
}
public function upper(): static
{
$this->str = strtoupper($this->str);
return $this;
}
public function build(): string
{
return $this->str;
}
}
// Before PHP 8.4 — parentheses required around new expression
$result = (new StringBuilder())->append('hello')->append(' world')->upper()->build();
// PHP 8.4 — no wrapping parentheses needed
$result = new StringBuilder()->append('hello')->append(' world')->upper()->build();
echo $result; // "HELLO WORLD"
// With constructor arguments
class Formatter
{
public function __construct(private string $prefix) {}
public function format(string $s): string { return $this->prefix . $s; }
}
echo new Formatter('[LOG] ')->format('hello'); // "[LOG] hello"
// Property access without parentheses
class Config
{
public string $env = 'production';
}
echo new Config()->env; // "production"
// Array access
class ArrayWrapper
{
private array $data;
public function __construct(array $data) { $this->data = $data; }
public function offsetGet(int $i): mixed { return $this->data[$i]; }
}
// echo new ArrayWrapper([1,2,3])[0]; // also works in PHP 8.4