Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127529 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id 811A51A00BC for ; Mon, 2 Jun 2025 12:50:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1748868476; bh=4CKDl6Hbjf/fZDkLSLneTb3P0RDdtX61yWci4rK5hWA=; h=From:Subject:Date:To:From; b=IgjAhQFo1+o1p8AqlfQlIXkEZIK5usbmRxOJVfcXDxJS25PVobi7t+RPWLB+6qL18 z2fHBPLZxj91oTvbpu6zzP654Xi4gQn0lj1PYbGhr+mOFdcPtMP8wNg1w1o/3a7EWl SJiMPQzuO92E/mctyb4qdAHKrxoMU/tgO2Eb9R7PFLoieQnnFtBkYXZDHvdtWq6w8p BLX6kfqVpEviwKWeJrztAh8J9M5/PHzVt835AdFk29w0nzdkug0SpwRc7LtLyT+z6c ggsTEHhHqxhoQeptBVd7Ci4K7Itz9tXUxziHZqXfPINvWub4JmekN2N6mAapi5EsgT zzi+xStv3BbRw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 52D3218006A for ; Mon, 2 Jun 2025 12:47:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: **** X-Spam-Status: No, score=4.9 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,HTML_MESSAGE, MANY_SPAN_IN_TEXT,RCVD_IN_SBL_CSS,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from avril.gn2.hosting (avril.gn2.hosting [84.19.162.247]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 2 Jun 2025 12:47:54 +0000 (UTC) Received: from avril.gn2.hosting (localhost [127.0.0.1]) by avril.gn2.hosting (Postfix) with ESMTP id 665DE1C4060F for ; Mon, 2 Jun 2025 14:49:58 +0200 (CEST) Received: from smtpclient.apple (unknown [113.210.105.67]) by avril.gn2.hosting (Postfix) with ESMTPSA id 62E0D1C40569 for ; Mon, 2 Jun 2025 14:49:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nicksdot.dev; s=default; t=1748868598; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=ooLO1lXiwEvFcrbJCuxNezAQS0mz56m7zpe0cs+5AbQ=; b=4ikkmKBkcfbWpCQ1fR/Yb7ui7Hh0oH8qtNK8LQx3m0voGVCa1lZ2YO076VTtQqlO6TVnH6 0gfwQi8s6+7pPVNFTO7Mv3EpV69pUi7+CTuIcKasHy5yhtaChkjMvGERMiAruZxi1mqEPF /HPT58cQfh2Xpubmk3MyanugGd2RLPwVpVp//2P9cdD6Kaw67znDkAcVS/ULXaqpVRdKNY 9VvR0h3hLrpkSUy5kj9Wgfg97AmFuWqIcEvILtSW59U5YGQKC705arUg9/QRa4FtFCcNw5 al1yv04lR9tTSVkW1oarYce3tNcNojeSPCh9s9FQYXCABLnXV5nQn3yBtbKGRQ== Authentication-Results: avril.gn2.hosting; auth=pass smtp.auth=php@nicksdot.dev smtp.mailfrom=php@nicksdot.dev Content-Type: multipart/alternative; boundary="Apple-Mail=_6E5F3EB4-39F3-4143-A652-B258B19753E4" Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3826.600.51.1.1\)) Subject: [PHP-DEV] Allow hooks in `readonly` promoted properties Message-ID: Date: Mon, 2 Jun 2025 20:49:39 +0800 To: internals@lists.php.net X-Mailer: Apple Mail (2.3826.600.51.1.1) X-Spamd-Bar: -- X-Spamd-Result: default: False [-2.60 / 15.00]; BAYES_HAM(-3.00)[100.00%]; MV_CASE(0.50)[]; MIME_GOOD(-0.10)[multipart/alternative,text/plain]; RCVD_COUNT_ZERO(0.00)[0]; NEURAL_HAM(-0.00)[-0.997]; ARC_NA(0.00)[]; MIME_TRACE(0.00)[0:+,1:+,2:~]; ASN(0.00)[asn:9534, ipnet:113.210.105.0/24, country:MY]; MID_RHS_MATCH_FROM(0.00)[]; FROM_HAS_DN(0.00)[]; DKIM_SIGNED(0.00)[nicksdot.dev:s=default]; FROM_EQ_ENVFROM(0.00)[]; RCPT_COUNT_ONE(0.00)[1]; TO_DN_NONE(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; SURBL_MULTI_FAIL(0.00)[nicksdot.dev:server fail,smtpclient.apple:server fail] From: php@nicksdot.dev (Nick) --Apple-Mail=_6E5F3EB4-39F3-4143-A652-B258B19753E4 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii Dear Internals, I am sending my first message here. Thank you all for your hard work! PHP has evolved amazingly over the past few years; I love it.=20 Promoted properties allow us to write very neat value objects, with = almost no boilerplate.=20 Now, with property hooks, we can eliminate even more boilerplate. However, there is a bummer.=20 When we want to use a set hook to add a simple mapper or validator, we = are have to deal with asymmetric visibility, and refactor the whole = class. Here in user land, I don't see a clear reason for that. Ideally, I would simply like to handle what will be set without having = to deal with the general visibility of the class or its properties. Currently, instead of: ```php=20 final readonly class Entry { public function __construct( public string $word, public string $slug, public string $file, public string $path, public array $lemmas { set(array $value) =3D> array_map(static function = (Lemma|array $lemma): Lemma { return $lemma instanceof Lemma ? $lemma : new = Lemma(...$lemma); }, $value); }, ) {} } ``` we must refactor our entire class and will arrive at: ```php=20 final class Entry // no more readonly { public function __construct( public readonly string $word, // added readonly public readonly string $slug, // added readonly public readonly string $file, // added readonly public readonly string $path, // added readonly private(set) array $lemmas { // added visibility set(array $value) =3D> array_map(static function = (Lemma|array $lemma): Lemma { return $lemma instanceof Lemma ? $lemma : new = Lemma(...$lemma); }, $value); }, ) {} } ``` The downsides are: - the class can no longer be `readonly` - each property must be set to `readonly` - hooked properties must use `private(set)` There are many unrelated things we need to think about just to use a set = hook. The example object is tiny and already then feels so much denser.=20 Think of a bigger object if you like. For each added property, we once = again must add the `readonly` keyword.=20 Unnecessary noise, IMHO. Personally, this puts me off adopting property hooks -- because right = now, a good old factory method is, subjectively, more clean/clear. I believe promoted properties should allowed for `readonly` properties = and in `readonly` classes.=20 This would help us to avoid the unnecessary boilerplate like outlined = above. That said, I would greatly appreciate if internals could explore to = allow `readonly` for hooks in promoted properties in 8.5. -- Cheers & thanks, Nick= --Apple-Mail=_6E5F3EB4-39F3-4143-A652-B258B19753E4 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=us-ascii
Dear Internals,

I am = sending my first message here. Thank you all for your hard = work!

PHP has evolved amazingly over the past few years; I love = it.
Promoted properties allow us to write very neat value objects, = with almost no boilerplate.
Now, with property hooks, we can = eliminate even more boilerplate.

However, there is a bummer. =
When we want to use a set hook to add a simple mapper or validator, = we are have to deal with asymmetric visibility, and refactor the whole = class.
Here in user land, =
I don't see a clear reason for that.
Ideally, I would simply like to handle what will be set =
without having to deal with the general visibility of the class or its =
properties.

Currently, = instead of:

```php =
final readonly class Entry
{
public function = __construct(
public string $word,
public string = $slug,
public string $file,
public string = $path,
public array $lemmas {
set(array = $value) =3D> array_map(static function (Lemma|array $lemma): Lemma = {
return $lemma instanceof Lemma ? $lemma : new = Lemma(...$lemma);
}, $value);
},
) = {}
}
```

we must refactor our = entire class and will arrive at:

```php =
final class Entry // no more readonly
{
public = function __construct(
public readonly string $word, // added = readonly
public readonly string $slug, // added readonly
= public readonly string $file, // added readonly
public = readonly string $path, // added readonly
private(set) array = $lemmas { // added visibility
set(array $value) =3D> = array_map(static function (Lemma|array $lemma): Lemma {
= return $lemma instanceof Lemma ? $lemma : new Lemma(...$lemma);
= }, $value);
},
) {}
}
```

The downsides are:

- the class can no longer be = `readonly`
- each property must be set to `readonly`
- hooked properties must use `private(set)`

There are many unrelated things we need to think about = just to use a set hook.
The example object is tiny and already then = feels so much denser.
Think of a bigger object if you like. For each = added property, we once again must add the `readonly` keyword.
Unnecessary noise, IMHO.

Personally, this puts me off = adopting property hooks -- because right now, a good old factory method = is, subjectively, more clean/clear.

I believe promoted properties = should allowed for `readonly` = properties and in `readonly` classes.
This would help us to avoid the =
unnecessary boilerplate like outlined above.

That said, I would = greatly appreciate if internals could explore to allow `readonly` for hooks in promoted properties in = 8.5.
--
Cheers & thanks,
Nick
= --Apple-Mail=_6E5F3EB4-39F3-4143-A652-B258B19753E4--