[php-src] Issue #22587: Fatal errors for property hooks in combination with pipes

[email protected] (NickSdot) Sat, 4 Jul 2026 08:20:53 +0000
Newsgroups php.bugs
Message-ID <[email protected]>
Issue: https://github.com/php/php-src/issues/22587
Author: NickSdot

### Description

Hey there! 

I came across the following...

```php
public string $path = '%s/foo/%s' {
    get => sprintf($this->path, $this->name, str_replace('output', '%s', basename($this->stub)));
}
```

which works. PHPStorm offers a refactor to:

```php
public string $path = '%s/foo/%s' {
    get => $this->stub
            |> basename(...)
            |> (fn($x) => str_replace('output', '%s', $x))
            |> (fn($x) => sprintf($this->path, $this->name, $x));
}
```

Which results in:

> Fatal error: Cannot specify default value for virtual hooked property

The RFC explicitly shows such example, although without default value. There is, however, no word about that using pipes in hooks would turn a backed hooked property into a virtual property. Hence, I would have expected it to work. Then I tried:

```php
public function __construct(
    public string $path = '%s/foo/%s' {
        get => sprintf($this->path, $this->name, str_replace('output', '%s', basename($this->stub)));
    }
) {}
```

Which  works, with and without passing `$path` to the constructor. Then I again apply the proposed refactor...

```php
    public function __construct(
        public string $path = '%s/foo/%s' {
            get => $this->stub
                    |> basename(...)
                    |> (fn($x) => str_replace('output', '%s', $x))
                    |> (fn($x) => sprintf($this->path, $this->name, $x));
        }
    ) {}
```

which with and without passing `$path` to the constructor results in:

> Fatal error: Uncaught Error: Property x::$path is read-only in

even though there is no `readonly` involved at all. 

Nothing of this seems expected to me. Feels similar to what was added as errata regarding arrow functions, but wrapping the whole thing into parentheses does not help (and is not mentioned in the RFC), and `get {}` has the same issues.

### PHP Version

```plain
PHP 8.5.7 (cli) (built: Jun  2 2026 20:59:56) (NTS)
Copyright (c) The PHP Group
Built by Homebrew
Zend Engine v4.5.7, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.7, Copyright (c), by Zend Technologies
```

### Operating System

macOS latest