Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125772 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 B351A1A00BD for ; Wed, 9 Oct 2024 15:01:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1728486223; bh=MCsXkRiu9FIJENuDPiIHVavk0GQbgBT/3AhSDjCQPJk=; h=From:Date:Subject:To:From; b=cDaNZzVf14gmWYJjE8QSq9r63WBKPw0UUpElQlFMbUBooF9aRmJrmqcrM0051cecM wr0v5qfDxqQjXF+aqLCkmQShyabAXUxFEtQOebl1LKPOyyy70PYxFHCYt1v6ZsqCF6 DVh8FQvszPU0+stAlnWK4l0wDnxQgVVFXmBqh9B5VS391BsKVzCR8S1gqpMTMdq+pE CSQv//S3ovVo2calG8VJqIdjD107w3R4D+qerboKa9gEiV6Ncckp8v8WiibJRyep1i wJ5N1s5j+0MUUbMvKIocgvmu0rzZSKLCDqdPieLywWcXdJc5LL8j1+M+hTyltfnulC 8yfDmjWzD2aoQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 2A565180041 for ; Wed, 9 Oct 2024 15:03:43 +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-wm1-f50.google.com (mail-wm1-f50.google.com [209.85.128.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 ; Wed, 9 Oct 2024 15:03:42 +0000 (UTC) Received: by mail-wm1-f50.google.com with SMTP id 5b1f17b1804b1-42e5e1e6d37so70933535e9.3 for ; Wed, 09 Oct 2024 08:01:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1728486084; x=1729090884; darn=lists.php.net; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=mCDuTP8wnl03vHhTl9pz0tmyqgL48BfGPYaizkq4sr8=; b=F1pNcbkr2tkNdHwoziTTPayU+nH35xO4+78F5gWAq8FMrPXXkj3mvWpMSYIUwuVIrT HFDCi6NyLBycN28ikOFJ2pv03eZHBBY9fXXxcSrLc5ua8nDA0cuSYUfiN22Nstfe4Kup 1SJZ5qAeP2ztCmC+wcwvYLgyRF3ZsXGWBfO1IeiLZ1xGz4uRLtE2YESR0wds3bgGABYa uNDx0vFI20/JmmJQAdKtFcsFX/p+lQVfYKkFIyDYHuhA0/reHnfjT9V0sgSNllZqnCRK H+s9swZqNyP2UOzibYfnW8kvYu2jU1V1sUlq/264en/jeQYF++TlXgNnRs8YEVcTafCZ HEDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728486084; x=1729090884; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=mCDuTP8wnl03vHhTl9pz0tmyqgL48BfGPYaizkq4sr8=; b=KhRh4Ad0E2DpXNWPnN9q+GAqhEYJG3iVHQ2jvVJHrV+QIzBw/217uAAwN59sjQyPmM e2TmnoWxHYnZ6e84OyA0J2wiyjDHdZtdGTCzpbzp2R2XgWOhiA8MOBvouzjDcCtu1gDK YeWbxbQbvOw8ob4x9qek4hKu8vprCy3OUoD5UTb7oayhEyrtlUaLOek/N9J5Co9HEinB B4DvHWB69KggW/+5lHJ2pP6sl7wEYHCO0wxP6DVrOpJFaZZ0QiSHjSRFDu0Q0ZSV6m9N vV7Kv+ju+Ylwh5tiN1wrFquw+RGr4So08pIIUE0mQx+Hz5FnhAxcxW7cAUwJYTw4ms2+ pogQ== X-Gm-Message-State: AOJu0Yz4qXSwnwLRdx5DloI+V6LxJpMqqIYWufi6mqnMXfT3esz8RpBv c8jIJD3v0Q9ehrS7zGzbmthSmbSyQzaCRIy3nenBmV9kPNxRBv3TJ/6jl0C/Tqx2ef4mp6nTA3s 8U/3kidhH9axDIE+VzwPAKXs3u4ZWTXtgVA== X-Google-Smtp-Source: AGHT+IGrqBAnfA0RT9CP2Ja4lNdyYwXfbp7FJYnaI9XIpVfaYaFQSZOjxsL+A/uWMmDbRCD1X/0h8e5ARnYl+nyndbo= X-Received: by 2002:a05:600c:5250:b0:426:6455:f124 with SMTP id 5b1f17b1804b1-430c3a9dfa6mr23802815e9.0.1728486083516; Wed, 09 Oct 2024 08:01:23 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Date: Wed, 9 Oct 2024 18:01:12 +0300 Message-ID: Subject: [PHP-DEV] Asymmetric visibility is a BC break To: php internals Content-Type: text/plain; charset="UTF-8" From: udaltsov.valentin@gmail.com (Valentin Udaltsov) Hi, internals! Since writing https://externals.io/message/125740 I've realized that the major problem with aviz is actually simple but fundamental. In PHP <=8.0 this code is valid for an object of any user class: ```php class User { public string $name = 'Bob'; } $object = new User(); foreach ($object as $property => $value) { $object->{$property} = 'Jack'; } ``` The same is true for Reflection API: once you check that `(new ReflectionProperty(Foo::class, 'property'))->isPublic()`, you can safely read property and write to it from any scope. Now let's jump to PHP 8.1+ with support for readonly properties. A readonly property is two functionalities in one: write-once and private set. This means that `public readonly $property` is actually `public(get) private(set) readonly $property`. Although it is marked as `public`, it is not public because it is not a symmetric public property! In PHP 8.1+, the following User class suddenly breaks the code above: ```php class User { public function __construct( public readonly string $name = 'Bob', ) {} } $object = new User(); foreach ($object as $property => $value) { // Fatal error: Uncaught Error: Cannot modify readonly property User::$name $object->{$property} = 'Jack'; } ``` In other words, the meaning of `public` has changed in PHP 8.1. Before, it used to mean "symmetric", now it means "symmetric unless readonly". While not explicitly stated in changelogs, this was a BC break, because a changed semantic of smth that existed before is a BC break. Did it break anything? Of course it did! See: - https://github.com/doctrine/orm/issues/10049 - https://github.com/symfony/symfony/pull/46840 - https://github.com/Ocramius/GeneratedHydrator/issues/656 - https://github.com/opis/closure/issues/129 I believe there are still many places where the concept of "public" needs to be adjusted to fully support readonly properties. Now in PHP 8.4 asymmetry will be made explicit and will allow users to specify visibility for setters. However, the core issue remains unresolved: ```php final class User { public function __construct( public private(set) string $name = 'Bob', ) {} } $object = new User(); foreach ($object as $property => $value) { // Fatal error: Uncaught Error: Cannot modify private(set) property User::$name from global scope $object->{$property} = 'Jack'; } ``` I'd like to draw your attention to the fact that aviz introduces a BC break, despite saying "Backward Incompatible Changes: None. This syntax would have been a parse error before." While the syntax is new, it allows one to alter the old concept of public by changing set visibility. What can we do about it: 1. Explicitly introduce the concept of getter and setter visibility, preserve `ReflectionProperty::isPublic()` behavior from PHP <=8.0 and add `ReflectionProperty::(get|set)Is(Public|Protected|Private)` methods. I have explained all these ideas in https://externals.io/message/125740 . If this option is chosen, aviz will likely need to be reverted and reintroduced in PHP 8.5, since we're already in the feature freeze period. 2. Proceed with the current approach, but clearly explain the BC break in the changelog, and merge this PR https://github.com/php/php-src/pull/16209 to mitigate reflection issues as outlined in https://externals.io/message/125740. -- Best regards, Valentin