Newsgroups: php.internals,php.internals Path: news.php.net Xref: news.php.net php.internals:128005 php.internals:128006 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 B29991A00BC for ; Fri, 11 Jul 2025 07:25:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1752218637; bh=/3+vzT8qRIbbEi2ueVrUhBmrY5eBGEM3Z0UMdC59sbI=; h=From:Subject:Date:In-Reply-To:Cc:To:References:From; b=d16R7g24IebiCSOLuiBSh7ibSUIoF16Qa2Tm8mnxRDgXkVEUcM5Jp7jBs5GEgxxqb n7bzi9phHq2H/ETBX8Li9SK6lDjYjQ3KkmP5AwYoYHWUWrzKldRuKjLYxWfEAirt++ /MqOXaf7VzKOCD0Ukyv27Nrud2n3Oah7q+sZ4OsRxDdt0hQUIeeIgtIAjMtXZ4CLUp A9txjQuCbD143TBZO0SZ5eoxVwIsEIGWZTrdIluE6DATHCA8rTKR7o+s9v1WjR1JgO zPH7U9RC1LfZhNQGy1p/KOEMGzfKVNDe6Z40didL1qXEJqhMN+ycbIJQbf2Uu+De3C 2Er/jKQ11Ll/g== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 23DF318005D for ; Fri, 11 Jul 2025 07:23:57 +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=-3.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,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 mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Fri, 11 Jul 2025 07:23:56 +0000 (UTC) Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-45348bff79fso21410175e9.2 for ; Fri, 11 Jul 2025 00:25:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1752218745; x=1752823545; darn=lists.php.net; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:from:to:cc:subject:date:message-id:reply-to; bh=y+5J5OZOENq/jvsI6C+HsHelyIbP/ZIQQKvddupvcsA=; b=JuVUVeMavw7D61w01pgduWBsmPjKUg9NrenBGpFhf5xwdzo08R4QwVe4tdsClIHtg2 lqpvueGh9htFWJARZliWqHIdiFdakSk9ALy7o4B8TtNmU6hFYaSU24QLfQE+kEZIKOri 7Ej8Ikr+Tf0hSQwplP0pnKv8MDqpzckfzSwyxufCABeyHgM6CUO3HFoadHcD66VsGXiI SwleyBTfjG3jVtaOttNv3xK4Ypoq4iMh+l+/V9ikVPd5I2Nrg2Jx0Js4DJRg4dNLqrHC 951k8o0nmz7bEt8DtcZVSKploFcQWKuGAwnxGwTnZ2vGe+Fufo3vTKuWsw1IQPgmEyDM nqQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752218745; x=1752823545; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=y+5J5OZOENq/jvsI6C+HsHelyIbP/ZIQQKvddupvcsA=; b=rvunS+TWIAqsFiaW4MjS5ZnLVfB8EFAxbhpoyIjlOwcAoQhAoSY9eBfCA+Jv4Fx0WW 3E63Nfz7YwC22p2WmUfncAfhcqt7Y42xXiITQrHmP85++0mKcAXNdrJHTnHFHz2wr0XZ PNCyP4BsIP4Rw1iU5g8h/qY38Tcf6qKjojWypXCW947AgDYXWCTMrhAy67tnFUwkaoXN kaWIu+eGjd8Ih5/HekvyCcAkRPAR4RpvNPvvnPCSfwn/gE9wduT+DBBXEwuiSlXrmtZk sfXzwTlGnLyEOItvQuvw8r/2lV1i6dIqUi5T4FFNNmGsE77u+ArMZ8n3t5PXiA/ki6n3 ypsg== X-Forwarded-Encrypted: i=1; AJvYcCWfWAxTh4/n+TU5B99QyCEqzo+5aO/GSUYNsd9zQ0ORscQkLN0wuJTwV+kj7K+cZ7NXOqUi5/8fRRY=@lists.php.net X-Gm-Message-State: AOJu0YzAfgfohCCXjgMTJnG75iBppJpkNA82CqhDSLpTy7SnXsuI7CA7 XAIXAXr/BDNrqEE3WvU3orqNOGGripHKzWQv8+8mDxDz8/Thb+rQ9SErVmpduA== X-Gm-Gg: ASbGncuREEk+5Vu6QT8rrtzE+v8eXb/b3fMbQOHjZRDJW43uSqqM0x/ljEtjqcwZ5OG 7oPnPy6EEi4rKHaoOxjY5OT4Ys/KbyTfk/k2VL/KtBDNJUtZBm53Y4XQms6lRkwm1OM4gCtl7W8 7TF4mEeQKKjRDmluF2TvQv4XQPhSVpeccCAjuBmZ0OJaQbQIuX5eXnz1BkP5FykhZ6qNgzEio4j tz60VexPHB70e17xs3d9xi8mq8lrgVSEfGuT9SwwMVMKRZZL51jZqpFYBUgq7gkpxtk3MGZsgCg ajCfQNVOb2Pm0AUdTwdSnt/RGHv6i5cwcj1vgarid5o9ARooUSkKni2PagldPYNaKqbO0aLiayp xx36ELPse65bT2wxMY32vzAn9j6YgD2S+QS3p7qwM X-Google-Smtp-Source: AGHT+IEmesuor8S0AVujTtCXS7qTaqGbmpsD5Y0VeKKR6GMeiMurXmbcKbRDDqUn/TwtGywJ6w79gQ== X-Received: by 2002:a05:6000:2088:b0:3b3:a6e1:135c with SMTP id ffacd0b85a97d-3b5f2e32f4fmr1051180f8f.42.1752218744760; Fri, 11 Jul 2025 00:25:44 -0700 (PDT) Received: from smtpclient.apple ([89.249.45.14]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-454d50ded8csm76181225e9.20.2025.07.11.00.25.43 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 11 Jul 2025 00:25:44 -0700 (PDT) Message-ID: <16BD443D-A179-465D-84A0-6E3780F62D8E@gmail.com> Content-Type: multipart/alternative; boundary="Apple-Mail=_B64DE083-6425-4708-8A64-059F673F9148" 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: Re: [PHP-DEV] [RFC] Readonly property hooks Date: Fri, 11 Jul 2025 09:25:33 +0200 In-Reply-To: <9D5043B2-1589-4FD5-B289-6E98FB1177BE@nicksdot.dev> Cc: Larry Garfield , php internals To: Nick References: <1e8634d7-ac1a-4025-b4e2-1948aabf5251@app.fastmail.com> <9D5043B2-1589-4FD5-B289-6E98FB1177BE@nicksdot.dev> X-Mailer: Apple Mail (2.3826.600.51.1.1) From: claude.pache@gmail.com (Claude Pache) --Apple-Mail=_B64DE083-6425-4708-8A64-059F673F9148 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > Le 11 juil. 2025 =C3=A0 06:30, Nick a =C3=A9crit : >=20 > Hey all, >=20 >> On 8. Jun 2025, at 11:16, Larry Garfield = wrote: >>=20 >> As Nick has graciously provided an implementation, we would like to = open discussion on this very small RFC to allow `readonly` on backed = properties even if they have a hook defined. >>=20 >> https://wiki.php.net/rfc/readonly_hooks >>=20 >> --=20 >> Larry Garfield >> larry@garfieldtech.com >=20 > To not get this buried in individual answers to others: >=20 > I came up with two alternative implementations which cache the = computed `get` hook value. > One leverages separate cache properties, the other writes directly to = the backing store. >=20 > Links to the alternative branches can be found in the description of = the original PR. > https://github.com/php/php-src/pull/18757 >=20 > I believe that these are fair solutions to address the concerns that = came up in the discussion, and I hope people will agree. >=20 > Cheers, > Nick Hi Nick, I think that the second alternative described as: =E2=80=9CCache computed get hook to it's backing store; never run the = hook again=E2=80=9D is near the most reasonable from my point of view (basing my judgment on = the description, as I have not looked the actual implementation), = although there are still some concerns. Advantages of that approach: 1. relatively to the first alternative solution: there is indeed no = point to have a cache separate from the backing-store, as the = backing-store is supposed to play that role in most cases; 2. relatively to the manual =E2=80=9C??=3D=E2=80=9D pattern, it works = correctly with nullable properties. Here are my remaining concerns: A. It may be confusing to have a getter that is not always called. B. The idea of returning the value directly from the backing-store if = initialised is useful also for non-readonly properties. (That can be = emulated with the =E2=80=9C??=3D=E2=80=9D pattern, but only if the = property is not nullable.) Both concerns may be resolved with the following amendment: * Introduce a `cached` modifier, that enables the caching semantics = (i.e., not executing the getter if the backing-store is initialised). The example from the RFC would be written as: ```php readonly class LazyProduct extends Product { private DbConnection $dbApi; =20 private string $categoryId; =20 public Category $category { cached get =3D> $this->dbApi->loadCategory($this->categoryId); } } ``` The `cached` modifier may be applied to any get hook, but it is = mandatory if the property is readonly. (In practice, the =E2=80=9Ccached get hook=E2=80=9D corresponds to my = originally proposed =E2=80=9Cinit hook=E2=80=9D, but with the advantage = of not having a separate hook.)=20 =E2=80=94Claude --Apple-Mail=_B64DE083-6425-4708-8A64-059F673F9148 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8

Le 11 juil. 2025 =C3=A0 06:30, Nick = <php@nicksdot.dev> a =C3=A9crit :

Hey all,

On 8. Jun 2025, at 11:16, Larry Garfield = <larry@garfieldtech.com> wrote:

As Nick has graciously = provided an implementation, we would like to open discussion on this = very small RFC to allow `readonly` on backed properties even if they = have a hook = defined.

https://wiki.php.net/rfc/readonly_hooks

--
=  Larry Garfield
=  larry@garfieldtech.com

To= not get this buried in individual answers to = others:

I came up with two alternative = implementations which cache the computed `get` hook value.
One = leverages separate cache properties, the other writes directly to the = backing store.

Links to the alternative = branches can be found in the description of the original = PR.
https://github.com/php/php-src/pull/18757

I believe that these are fair solutions to address the concerns = that came up in the discussion, and I hope people will = agree.

Cheers,
Nick
<= /div>


Hi = Nick,

I think that the second alternative = described as:

=E2=80=9CCache computed get hook = to it's backing store; never run the hook = again=E2=80=9D

is near the most reasonable from = my point of view (basing my judgment on the description, as I have not = looked the actual implementation), although there are still some = concerns.

Advantages of that = approach:

1. relatively to the first = alternative solution: there is indeed no point to have a cache separate = from the backing-store, as the backing-store is supposed to play that = role in most cases;

2. relatively to the manual = =E2=80=9C??=3D=E2=80=9D pattern, it works correctly with nullable = properties.

Here are my remaining = concerns:

A. It may be confusing to have a = getter that is not always called.

B. The idea = of returning the value directly from the backing-store if initialised is = useful also for non-readonly properties. (That can be emulated with the = =E2=80=9C??=3D=E2=80=9D pattern, but only if the property is not = nullable.)

Both concerns may be resolved with = the following amendment:

* Introduce a `cached` = modifier, that enables the caching semantics (i.e., not executing the = getter if the backing-store is = initialised).

The example from the RFC would be = written as:

```php
readonly class = LazyProduct extends Product {

  =  private DbConnection $dbApi;
 
  =  private string $categoryId;
 
  =  public Category $category {
      =  cached get =3D> = $this->dbApi->loadCategory($this->categoryId);
  =  }
}
```

The `cached` = modifier may be applied to any get hook, but it is mandatory if the = property is readonly.

(In practice, the = =E2=80=9Ccached get hook=E2=80=9D corresponds to my originally proposed = =E2=80=9Cinit hook=E2=80=9D, but with the advantage of not having a = separate = hook.) 

=E2=80=94Claude

=



= --Apple-Mail=_B64DE083-6425-4708-8A64-059F673F9148--