Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:128118 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 D33A51A00BC for ; Fri, 18 Jul 2025 16:48:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1752857198; bh=Ec8VZBvNzkXfxVJ3XbQbahB8ExIoXTjVEea3vE2ekuo=; h=References:In-Reply-To:Reply-To:From:Date:Subject:To:Cc:From; b=e/4iBbIijqIRhBy6AxaaojOePEK4FvzzKx7pN7XynDGFHOt6xeHEI8/RsSZbasxmT P9bSpefADN/hHo9ejoUaKsLvGM7UUlGtgWT73Pp4f6fygCtkiABEdX7lNd6mmpqj1/ MnKhvdUqMVhhCnFV/B880uVWpfl/ra6HoUdhExrzcr0RUuUJ3FZOAK24wtqIlwmfhb 3Yo0oLep0VBvPHsh9sRFIR38gEAKC2VOx7PoGZJPeyBUOQkk6ABI0531BRb2p1qOwK 6KdyxsNNqOk7MxjhLQ2asASupWv3UxcSU0SADwkUB5LCw63kcgBPiv/jVxvlvZTaMa U0m1iediSJk+Q== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 091FE1801D4 for ; Fri, 18 Jul 2025 16:46:38 +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=-0.7 required=5.0 tests=BAYES_05,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, FREEMAIL_REPLYTO,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-il1-f171.google.com (mail-il1-f171.google.com [209.85.166.171]) (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, 18 Jul 2025 16:46:37 +0000 (UTC) Received: by mail-il1-f171.google.com with SMTP id e9e14a558f8ab-3e28be470f1so10869845ab.0 for ; Fri, 18 Jul 2025 09:48:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1752857304; x=1753462104; darn=lists.php.net; h=content-transfer-encoding:cc:to:subject:message-id:date:from :reply-to:in-reply-to:references:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=dAr7ntHaE87YU1BHK+/TKqAdyazDOEYJCDLS9Lu/BO4=; b=XYRVH1oNV86AcAw/YPbB7LSMlIKAXSV82s19HFcDIUGLor7rUu9/aggoCvZDxUftyk PbRGwwiiYL0TcsLDYL5CD49nKKM+o52ohNCvKCHokUN7EtzuyMW/ijepbLcUPpn0g4Sk n+NDTXMuA5qaOhNHMquXOrlnBlUe6Vsv0dEJgnpzqOSwG6rtVscs5jJJPbgdpzrYxolh 6PaP6Bkug9Xwd2TXsM/zlbje3D9dUsznWoqi3/2iammarSkVLDoYm8pNoCynFIeh8Jey O/M3WtY2SUgM20P3/izgJPGVplSIaalsiXHJZoxq57CoetUIuF7vel7Goh4LDDUhj/y+ bLSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752857304; x=1753462104; h=content-transfer-encoding:cc:to:subject:message-id:date:from :reply-to:in-reply-to:references:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=dAr7ntHaE87YU1BHK+/TKqAdyazDOEYJCDLS9Lu/BO4=; b=gsoKtCa7yUQOj+mropEEunFG6H5oO/clb3UFMgJ88pfb1M0ou8WnFNQcvaejkqWN2S JJAmWlUsg8XJ+I6qGYcrM4M2jMcOYkiqOyZwQcjZENCosWmuf0oxwgFdQyKwREWnWkI9 Ji54EwdAgFFAzyjwgmnDM2Yvi6iywlUjIVFz7VTmurd6JlL8xwnELzMnfmH/S9p+hPXj szDIoZLIbe+k4a6DqoSfc9z+ltORsJsT83VNU9ryYJGL5+b4pQ7SekgUbzCiRhTuI6Hk Qj9w5kPnz06t2DnvC92mkD8pNjyh9v3XAhHlFcXv0kMHua1P5fiXowfrTag88pi5nYIi uo0Q== X-Forwarded-Encrypted: i=1; AJvYcCUoWIZfGBGpxs1Hiaz8ZE7M3Q/QOgJlxOJpEQTG3NgGGi2hY4Iar7YwLbW0BLlkh2hCMRavHL9KKoU=@lists.php.net X-Gm-Message-State: AOJu0YwH60CjALuTM4vqmZ3z6TQ1eh/SLgX+ZVuQ0kW6XHaLjg8FbQBG agjU73OOkjwymz1szlYOuIAl+ptFoowYBEsfseuDSuJ5yb8c6Lh+EFajEkKIUkLgNrE3g34VXjq XecUdqFJ22oiX5NEGLr7ngKL/1bCsouIwciBM X-Gm-Gg: ASbGncveAHzZGqNCVIFvd9glUt/KIc4LEYug5ibF44cxGaXOosKNOOe5MHHhWUODLiE oBOJ+XMoNjl6tNb+LwY2T8CFp0LzknAHu7JZ4588DYODOtScdIwBZu5cVYaFw/JblTmLfMAYXb+ qJDJAc9B929Auy5hZhZHndM8ue623lBesKWvwRGnZ6yphH8zd6GDXt29bLG+HgGv46P0STM8N5X h9uS8ony5Pnvi09HzLkV88xHF3NQ1WywtK/vGEZ X-Google-Smtp-Source: AGHT+IFl4rvnKMVOYxx1qXDI15A5svVNf4CE+Y9QShDYWZcPz0kNlDPS8fxoL8pxJPZsRdH3qVV1XSCOK8yJiiMl8+k= X-Received: by 2002:a05:6e02:380d:b0:3e1:25b6:2a9a with SMTP id e9e14a558f8ab-3e295a1c481mr41238115ab.6.1752857303558; Fri, 18 Jul 2025 09:48:23 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <1e8634d7-ac1a-4025-b4e2-1948aabf5251@app.fastmail.com> <9D5043B2-1589-4FD5-B289-6E98FB1177BE@nicksdot.dev> <0856c89f-2000-448a-bbbf-c145a8699f6a@app.fastmail.com> <2641b8bc-6337-4b75-a5a3-93dee1b03796@bastelstu.be> <0d9a2968-26dd-43dd-9733-d2eb621ab9ec@app.fastmail.com> In-Reply-To: <0d9a2968-26dd-43dd-9733-d2eb621ab9ec@app.fastmail.com> Reply-To: erictnorris@gmail.com Date: Fri, 18 Jul 2025 12:48:07 -0400 X-Gm-Features: Ac12FXxQc8ZiKAQX8Z0loWnWhinzoVkAn5VpvT8xHjRfNOwTxjwk70ikQ90XJmw Message-ID: Subject: Re: [PHP-DEV] [RFC] Readonly property hooks To: Rob Landers Cc: =?UTF-8?Q?Tim_D=C3=BCsterhus?= , Larry Garfield , php internals Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable From: eric.t.norris@gmail.com (Eric Norris) On Fri, Jul 18, 2025 at 12:01=E2=80=AFPM Rob Landers wr= ote: > > > > On Fri, Jul 18, 2025, at 17:25, Tim D=C3=BCsterhus wrote: > > Hi > > On 7/14/25 15:38, Larry Garfield wrote: > > Thanks, Ilija. You expressed my concerns as well. And yes, in practic= e, readonly classes over-reaching is the main use case; if you're marking i= ndividual properties readonly, then just don't mark the one that has a hook= on it (use aviz if needed) and there's no issue. > > A readonly class is not just a convenience shortcut to mark each > individual property as readonly. It has important semantics of its own, > because it forces child classes to also be readonly. And even for final > classes it communicates to the user that "I won't be adding non-readonly > properties to the class". > > > Wasn=E2=80=99t that the entire point of readonly classes? Because it was = painful to write readonly for every property. Then if a property is readonl= y, the inherited property is also readonly, so, by extension: a class exten= ding a readonly class is also readonly. > > There=E2=80=99s no =E2=80=9Ccommunication=E2=80=9D here; just logic. > > > Marking a class as readonly must therefore be a deliberate decision, > since it affects the public API of your class and in turn also user > expectations. > > > Not really. I can remove the readonly designation and manually mark every= property as readonly. The behavior of the class doesn=E2=80=99t magically = change. Or, at least, I hope it doesn=E2=80=99t. > > > > Perhaps we're thinking about this the wrong way, though? So far we've = talked as though readonly makes the property write-once. But... what if we= think of it as applying to the field, aka the backing value? > > I think of readonly from the view of the public API surface of an > object. The property hooks RFC was very explicit in that property hooks > are intended to be =E2=80=9Ctransparent to the user=E2=80=9D and can be a= dded without > breaking the public API. In other words: Whether or not a property is > implemented using a hook should be considered an implementation detail > and as a user of a class I do not care whether there is a backing value > or not. > > > So readonly doesn't limit calling the get hook, or even the set hook, m= ultiple times. Only writing to the actual value in the object table. That= gives the exact same set of guarantees that a getX()/setX() method would g= ive. The methods can be called any number of times, but the stored value c= an only be written once. > > As a user of a class the "backing table" is mostly inaccessible to me > when interacting with objects. It's only exposed via var_dump() and > serialize(), the former of which is a debug functionality and the output > of latter not something I must touch. > > > It would not guarantee $foo->bar =3D=3D=3D $foo->bar in all cases (thou= gh that would likely hold in the 99% case in practice), but then, $foo->get= Bar() =3D=3D=3D $foo->getBar() has never been guaranteed either. > > Properties and methods are something different. For methods there a > reasonable expectation that *behavior* is associated with them, for > properties there is not. > > > Unless I missed something. Hooks are fancy methods? There is nothing intr= insic about object properties. There is nothing that says two calls to the = same property=E2=80=99s getters are going to result in the same values. The= re is asynchronous php, declare ticks, etc. especially in the case of globa= ls, there is no guarantee you even have the same object. At the end of the = day, it is up to the programmer building that system / program to provide t= hose guarantees=E2=80=94 not the language. I do think that, without any additional information, it would be reasonable to assume that `$foo->bar =3D=3D=3D $foo->bar`, i.e. there would not be side-effects until you've called a method or written to the object in some way. So I share Tim's opinion here, but I do agree that with hooks available this is not actually a guarantee. You could certainly have a `$foo->random_value` property and document that it will be different each time you call it. That said, once the programmer has added the readonly designation to a property, I do think that something says that two calls to the same property will result in the same values - the readonly designation. I disagree with the point that it's not up to the language - the language should provide an affordance for enforcing programmer intent, and I see no reason to even have a readonly designation if we're going to make it easily circumventable or otherwise just a "hint". It seems that one common counterpoint to the "let's not make it circumventable" argument is to point out that it's already circumventable via __get. I agree with Claude that this is not a justification for making it *easier* to circumvent. I would also like to note that the original RFC (https://wiki.php.net/rfc/readonly_properties_v2#unset) seems to allow this behavior *for the purpose of lazy initialization*. With an `init` hook, we'd have solved this problem, and could deprecate the `__get` hack for `readonly` properties / classes. Nicolas Grekas said "__get is certainly not legacy; removing it would break many use cases without proper alternatives.", but note that I'm only suggesting we could maybe deprecate __get for `readonly` properties once we had an `init` hook - I'm not proposing deprecating it generally. Without a counterexample, I don't think there would be another reason for `__get` to work with `readonly` properties.