Skip to content

Instantly share code, notes, and snippets.

@azjezz

azjezz/RFC.md Secret

Last active Apr 24, 2021
Embed
What would you like to do?
<?php
interface Throwable seals Exception, Error {}
class Closure seals Partial {}
interface Throwable for Exception, Error {}
class Closure for Partial {}
sealed interface Throwable permits Error, Exception {}
sealed class Closure permits Partial {}

Introduction

A sealed class can be extended directly only by the specified classes. Similarly, an interface that is sealed can be implemented directly only by the classes listed.

Classes mentioned in the sealing list can themselves be extended arbitrarily unless they are final or also sealed.

In this way, sealing provides a single-level restraint on inheritance.


The purpose of the feature should not be conflated or confused with the goals of something like package-private classes or namespace visibility, in general.

Proposal

Support for sealed classes is added through a new keyword, seals.

Basic usage

Sealed Classes

namespace Typing;

interface Type { ... }

class StringType implements Type { ... }
class IntegerType implements Type { ... }
class FloatType implements Type { ... }

sealed class UnionType permits NumberType, KeyType implements Type
{
  public function __construct(
    protected array $types
  ) {}
  
  ...
}

// ok
final class NumberType extends UnionType {
  public function __construct() {
    parent::__construct([new IntegerType, new FloatType]);
  }
}

// ok
final class KeyType extends UnionType {
  public function __construct() {
    parent::__construct([new IntegerType, new StringType]);
  }
}

// Error: Class ScalarType may not inherit from sealed class (UnionType)
final class ScalarType extends UnionType {
  public function __construct() {
    parent::__construct([new IntegerType, new FloatType, new StringType]);
  }
}

Sealed Interface

sealed interface UserInterface permits ExtendedUserInterface, User
{
}

// ok
interface ExtendedUserInterface extends UserInterface
{
}

// ok
final class User implements UserInterface
{
}

// Error: Interface SuperUserInterface may not inherit from sealed interface (UserInterface)
interface SuperUserInterface extends UserInterface
{
}

// Error: Class MyUser may not inherit from sealed interface (UserInterface)
final class MyUser implements UserInterface
{
}

Sealed Traits

example from symfony/cache - simplified

namespace Symfony\Component\Cache\Traits {
  use Symfony\Component\Cache\Adapter\FilesystemAdapter;
  use Symfony\Component\Cache\Adapter\FilesystemTagAwareAdapter;

  sealed trait FilesystemTrait permits FilesystemAdapter, FilesystemTagAwareAdapter { ... }
}

namespace Symfony\Component\Cache\Adapter {
   use Symfony\Component\Cache\Traits\FilesystemTrait;

   // ok
   final class FilesystemAdapter {
     use FilesystemTrait;

     ...
   }

   // ok
   final class FilesystemTagAwareAdapter {
     use FilesystemTrait;

     ...
   }
}

namespace App\Cache {
    use Symfony\Component\Cache\Traits\FilesystemTrait;
   
    // Error: Class App\Cache\MyFilesystemCache may not use sealed trait (Symfony\Component\Cache\Traits\FilesystemTrait)
    final class MyFilesystemAdapter {
      use FilesystemTrait;
    }

    // Error: Trait App\Cache\MyFilesystemTrait may not use sealed trait (Symfony\Component\Cache\Traits\FilesystemTrait)
    trait MyFilesystemTrait {
      use FilesystemTrait;
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment