Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125750 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 qa.php.net (Postfix) with ESMTPS id 416C11A00BD for ; Fri, 4 Oct 2024 16:13:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1728058557; bh=3BhgWesK/EE2I83F83mAstHbUTo9SfAsMQOhChrnz/Y=; h=References:In-Reply-To:From:Date:Subject:To:From; b=Nju6Zjs9qRLkL/QtUjC0B6sDXZ2eFZv1u9g6H5sKhx7F1lU6jkgQvU1bbUamDLOr4 yTyyWRj7eqju8HZtWRF1ZCnF5DVvDf6IbslsV3dNk+3kTimpNtzp1Q1TrQLAmK9SJC NaDSZxdyeGJQVedfC2pyXtVNYCddJwj1wRusCCGAiE1I1Z2NFr865S4W5IaUBQPmyF vPw8wvLRkYv3b3VBGPTrA+C0UJW8urR8M9nCXooNwqLp+bJGIzOvoSnhhGq9hbmqZG a+pqS95kBB1TcyZpXEALX7fGHXjHGvsVMSHRXZQpic6Zp3EJea/eiNJ5DOLmcFhNR/ IVTUIcI+mAkkw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id CB62718007A for ; Fri, 4 Oct 2024 16:15:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-qv1-f50.google.com (mail-qv1-f50.google.com [209.85.219.50]) (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, 4 Oct 2024 16:15:56 +0000 (UTC) Received: by mail-qv1-f50.google.com with SMTP id 6a1803df08f44-6cb321145easo19765606d6.1 for ; Fri, 04 Oct 2024 09:13:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1728058420; x=1728663220; darn=lists.php.net; h=content-transfer-encoding:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=t6/BRb2G3QewLcBbRX64iwOKQ/2FVtwRnhZxpVVvxWY=; b=fPfKUvlIxmvsg9sdVWopaAE09I7zGCq3hr/Jv1PV+PUtjOAnerSD2uGtB8AsC/r1DW w79RI0+lX14bcdp9Dby1xQCXPbe+XDWD0kZBxhvbAGOJmmut/D3Sc1v+gTnTriXoruYY GOu50WguoBBtRia6hvuBSNUvXcwd4N24sX1IudQ1YDa+tQuv3NGJyDCxHh0sNmxMloyU Y2117nSKVMXQlSs3HxkCYzb21JzG1eHquSjBBUJNK6znTGRcY8lopTUL5xyyoCULsQAq 8Pvz6Q1hA1Eg+glaicjd12VAc5V/V/JxqAIvCKxNB2Q+TCNANE4BHNihPgPVMwMROMDW kDRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728058420; x=1728663220; h=content-transfer-encoding:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=t6/BRb2G3QewLcBbRX64iwOKQ/2FVtwRnhZxpVVvxWY=; b=Na15qQx6OxhKVOFZjKv0dvy1776K9/y7Yosj6EmQN6dUrcYnZPjg5bS6rzTs/t+ERG axwxttllCrfVD+xZXKPwFCFvOnc3OvEo3reFlappaYxgvyxujDlqBy6U6sR5Y4VvllcR NKiB/I/uL5HPhbEMUI+pfbSo21455PWGhJ9/7hxkwgfF8/guSkNpMclxEK9TJu2SyLsx QQXbECbiItRF1KrOGXV9ynxfGycklDLWKCdsJUe/WA+lGvfPOq+ldoH6JKg5+4J4Rn1O PY2RPaCEuOJjpia0oV08ZemwiyvVVskPZt+U6fD3F/Nj+LD2ZIuRwmZ+oMwbbx/inL6X vwDg== X-Gm-Message-State: AOJu0YzWkNpsPRPIVzNlQGRBbDEGK4hXMA61MgynRCDZGBEocJSaablP O5PiOCgmLaHe/81GkjPSPE10KTR7Xq4wONX8aeTbaSm7W1AEx08Zat4knw6p3Elt89CwGZpXqpI 0dB+CIexQ3F71ggH3In1QqofuxPxF74YFV7m+lA== X-Google-Smtp-Source: AGHT+IFtbBHhvG1dLc8ImL68B11YO7I0QbjynRkD2pUErVmowxYdUry2A5tFNMaWC0i16/sv5iOjXovdD6Diwzn8Tmo= X-Received: by 2002:a05:6214:5c07:b0:6cb:81ba:8ac1 with SMTP id 6a1803df08f44-6cb9ac0dc74mr52699776d6.0.1728058419904; Fri, 04 Oct 2024 09:13:39 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Fri, 4 Oct 2024 18:13:29 +0200 Message-ID: Subject: Re: [PHP-DEV] Asymmetric visibility Reflection API problems To: php internals Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable From: tovilo.ilija@gmail.com (Ilija Tovilo) Hi Valentin Thank you for bringing up your concerns. On Thu, Oct 3, 2024 at 3:32=E2=80=AFPM Valentin Udaltsov wrote: > > We are going to talk about the asymmetric visibility RFC [2] and the > new `ReflectionProperty::is(Private|Protected)Set()` > methods. Consider a class and reflected facts about it's properties [3]: > > ```php > class A > { > // isPrivateSet() =3D true (OK) > public private(set) mixed $public_private_set; > > // isPrivateSet() =3D false (I would expect true) > private private(set) mixed $private_private_set; > > // isPrivateSet() =3D false (I would expect true) > private mixed $private; > > // isProtectedSet() =3D true (OK, explained in the RFC) > public readonly mixed $public_readonly; > > // isProtectedSet() =3D false (I would expect true) > protected readonly mixed $protected_readonly; > > // isProtectedSet() =3D false (I would expect true) > protected protected(set) readonly mixed $protected_protected_set_read= only; > > // isPrivateSet() =3D false (OK), isProtectedSet() =3D false (OK) > public bool $virtual_no_set_hook { get =3D> true; } > } > ``` As mentioned on GitHub, I do understand and agree that this may seem confusing without more context. However, this behavior for flags is really not unique to asymmetric visibil= ity. For example: ```php interface I { public function test(); } var_dump((new ReflectionMethod('I', 'test'))->isAbstract()); //> bool(true) ``` The `abstract` flag is not (and cannot) be specified explicitly, but it is = added implicitly. Similarly, the `protected(set)` in `protected protected(set)` i= s redundant, so the compiler removes it to omit additional visibility checks.= For the same reason, we don't even have an internal flag (at runtime) for `public(set)`, as it is always removed at compile time. As mentioned, these methods are generally quite "dumb" and simply expose th= ese internal flags to userland. This is reflected by `getModifiers()`, which re= turns a bitmask over all flags. `getModifiers()` should stay consistent with `isPublic()`, as well as all the other methods. This will be increasingly difficult if we start tweaking the implementation of these methods. I have proposed to instead solve this by introducing new functions, `ReflectionProperty::isReadable()` and `isReadable()`. They would not only handle visibility and asymmetric visibility, but also scope, virtual-ness, hooks and readonly (including __clone). Additionally, if some new concept is ever added, the functions may adapt. I have created a simple PoC [1]. > Here's what I propose: > > - `ReflectionProperty::isPublic()` returns `true` only if the property > is symmetrically public. For `public readonly $prop` > it will return `false`, because it's implicitly `public protected(set) > readonly $prop`. This is a BC break, but a > smaller one, given that libraries now take "readonly" into account. > - `ReflectionProperty::isProtected()` returns `true` only if the > property is symmetrically protected. For `protected readonly $prop` > it will return ``true``, because it's implicitly `protected > protected(set) readonly $prop`. Fully backward compatible. > - `ReflectionProperty::isPrivate()` returns `true` only if the > property is symmetrically private. Fully backward compatible. > - Add `ReflectionProperty::isPublicGet()`: returns `true` if property > is `public` or `public XXX(set)`. > - Add `ReflectionProperty::isProtectedGet()`: returns `true` if > property is `protected` or `protected XXX(set)`. > - Add `ReflectionProperty::isPrivateGet()`: returns `true` if property > is `private` or `private private(set)`. > - Add `ReflectionProperty::isPublicSet()`: returns `true` if property > is symmetrically public (asymmetric public > set is not possible). > - Change `ReflectionProperty::isProtectedSet()`: returns `true` if > property is symmetrically protected or has an > asymmetric protected set. > - Change `ReflectionProperty::isPrivate()`: returns `true` if property > is symmetrically private or has an asymmetric > private set. I very much disagree with changing `isPublic` and friends. It would be a considerable BC break which isn't acceptable in the RC phase. I also don't = think it's necessarily more correct. With this RFC, properties have two visibilit= ies: 1. The visibility of the entire property, which we are all used to. 2. The visibility of the set operation, which was introduced with asymmetric visibility. Essentially, the get operation continues to inherit the visibility from the property. This is what `isPublic()` and friends are referring to. Of course= , you may argue that an equally valid mental model is that the property no longer= has a visibility, but an additional get visibility. However, this does not accurately reflect the implementation, nor, more importantly, the syntax. > The most difficult question is whether we can have these or similar > changes in 8.4 after RC1... Does a BC break > in the current implementation (if we agree that it exists) give us > such an option? > > Also, Ilija has a brilliant idea to add `isReadable($scope): bool`, > `isWritable($scope): bool` methods [5], > but this can be done in PHP 9. Normally: No. Breaking changes or new features (since very recently [2]) ar= e not allowed in the RC phase, which we have entered Sep 26th. If an exception we= re to be made, two new functions would have a much lower impact than tweaking the behavior of some very old functions. I'm not sure whether this is something= we necessarily need in 8.4. I have deferred this decision to the RMs. Also note that such functions wouldn't need to wait for PHP 9, it may also = go into the next minor. The next version of PHP is likely going to be 8.5, unl= ess we find a good reason to bump the major version. Regards, Ilija [1] https://github.com/php/php-src/pull/16209 [2] https://wiki.php.net/rfc/release_cycle_update#disallow_new_features_in_= release_candidates_and_bug_fix_releases