xp-framework / compiler

Compiles future PHP to today's PHP.
19 stars 0 forks source link

Support asymmetric visibility #182

Closed thekid closed 2 months ago

thekid commented 2 months ago

Add support for https://wiki.php.net/rfc/asymmetric-visibility-v2

Example

In a nutshell:

class Person {
  public private(set) string $name= 'Test';
}

$person= new Person();
echo $person->name;       // OK
$person->name= 'Changed'; // Visibility error

RFC status: Accepted

Quoting https://externals.io/message/124622#124838:

The final result is 24 Yes, 7 No, for a total of 77.4% in favor.

The RFC has passed. Thanks everyone for your participation and input. Ilija will get the PR merged soonish.

Rewriting

To support this in lower PHP versions, we will need to rewrite this to virtual properties, much like readonly support was implemented in #124, along the lines of the following:

class Person {
  private $_name;

  public function __get($name) {
    if ('name' === $name) return $this->_name;
  }

  public function __set($name, $value) {
    if ('name' === $name) {
       $caller= debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];
       $scope= $caller['class'] ?? null;

       // For private, just compare; for protected, use instanceof
       if (__CLASS__ !== $scope) {
         $from= $scope ? 'scope '.$scope : 'global scope';
         throw new Error('Cannot access private '.__CLASS__.'::$'.$name.' from '.$from);
       }

       $this->_name= $value;
    }
  }
}

$person= new Person();
echo $person->name;       // OK, triggers __get('name')
$person->name= 'Changed'; // Visibility error, triggers __set('name', 'Changed') from scope NULL

See also

thekid commented 2 months ago

The reflection library has support for this now, see https://github.com/xp-framework/reflection/releases/tag/v3.2.0 and https://github.com/xp-framework/reflection/releases/tag/v2.15.0

thekid commented 2 months ago

Implemented in https://github.com/xp-framework/compiler/releases/tag/v9.2.0

thekid commented 2 months ago

Once the PR is merged and built into GitHub Actions's 8.4 build, we can remove the featzre availability checks from the PHP 8.4 emitter using the following patch:

diff --git a/src/main/php/lang/ast/emit/PHP84.class.php b/src/main/php/lang/ast/emit/PHP84.class.php
index a23910d..71379f3 100755
--- a/src/main/php/lang/ast/emit/PHP84.class.php
+++ b/src/main/php/lang/ast/emit/PHP84.class.php
@@ -1,6 +1,5 @@
 <?php namespace lang\ast\emit;

-use ReflectionProperty;
 use lang\ast\types\{
   IsArray,
   IsFunction,
@@ -20,10 +19,6 @@ use lang\ast\types\{
  */
 class PHP84 extends PHP {
   use RewriteBlockLambdaExpressions;
-  use PropertyHooks, AsymmetricVisibility {
-    PropertyHooks::emitProperty as emitPropertyHooks;
-    AsymmetricVisibility::emitProperty as emitAsymmetricVisibility;
-  }

   public $targetVersion= 80400;

@@ -58,25 +53,4 @@ class PHP84 extends PHP {
       IsGeneric::class      => function($t) { return null; }
     ];
   }
-
-  protected function emitProperty($result, $property) {
-    static $asymmetric= null;
-    static $hooks= null;
-
-    // TODO Remove once https://github.com/php/php-src/pull/15063 and
-    // https://github.com/php/php-src/pull/13455 are merged
-    if (
-      !($asymmetric ?? $asymmetric= method_exists(ReflectionProperty::class, 'isPrivateSet')) &&
-      array_intersect($property->modifiers, ['private(set)', 'protected(set)', 'public(set)'])
-    ) {
-      return $this->emitAsymmetricVisibility($result, $property);
-    } else if (
-      !($hooks ?? $hooks= method_exists(ReflectionProperty::class, 'getHooks')) &&
-      $property->hooks
-    ) {
-      return $this->emitPropertyHooks($result, $property);
-    }
-
-    parent::emitProperty($result, $property);
-  }
 }
\ No newline at end of file
thekid commented 2 months ago

Merged in https://github.com/php/php-src/commit/8df557ac42c8227d8e7573f6a3a8d799ef28e7cd

thekid commented 2 months ago

PHP 8.4 on Ubuntu is not yet up-to-date with current GIT, see https://github.com/xp-framework/compiler/actions/runs/10643910513/job/29508056545.

thekid commented 2 months ago

PHP 8.4 emitter released in https://github.com/xp-framework/compiler/releases/tag/v9.3.0

thekid commented 2 months ago

See https://github.com/thekid/dialog/pull/61