symfony / polyfill

PHP polyfills

Home Page:https://symfony.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

8.1 Enum Polyfill

marc-mabe opened this issue · comments

Hi,

I have created a proof of concept to emulate enumerations for PHP < 8.1.

The code still WIP but the basics are working already - see https://github.com/marc-mabe/php-enum-polyfill
This way it's possible to write compatible code by still being able to take advantages of native enumeration support.

The main disadvantages are:

  • You have to use a magic function call to access enum cases MyEnum::MY_CASE() instead of MyEnum::MY_CASE
  • You have to manage your enumerations two times (polyfill version + native version)
  • Your native enumerations need to include a trait as BC layer

Would you consider to add something like this to symfony/polyfill project?

The fact that you have to write different code means that it is not actually a polyfill. So this is out of scope of this repo.

The goal of the polyfills is that you write your code the modern way.

Hi @stof,

Thanks for your fast reply.

I totally understand your concerns and also agree with you.

I still think that such "polyfill" or however it could be named has a lot of value in itself so I'll work on making it an own package.

I come an issue with your current polyfill version for 8.1 for enum_exists https://github.com/symfony/polyfill/blob/main/src/Php81/bootstrap.php#L23 . This would prevent users from using your library as well the enum library together.
Should I open another issue for that or do you know how I could force my version to be loaded before your version?

@marc-mabe making your own fake enum that must not be used like an actual PHP 8.1 enum report true in enum_exists looks wrong to me. Code using enum_exists would assume that such enums are used in the standard way.

@stof I would like to keep the differences as small as possible to make it as simple as possible for users to work with it as normal and also to remove it later on PHP < 8.1 is not a thing anymore.

Currently I'm testing for instanceof UnitEnum but I want to change that to an own unique class instanceof UnitEnumPolyfill to make sure it returns true for a known emulated enum only and not for anything else imlementing this interface for whatever reason.

The point here is that if someone uses enum_class it has only any value if enums are supported - that means if the code is either running on 8.1 or it's using the emulated version. I can't come up with a valid use case elsewhere.

@marc-mabe but my whole point is that your enum library does not expose the actual enum API (which cannot be polyfilled). As the usage cannot be the same, making enum_exists would break things. If a library does a enum_exists and then use the enum API based on that, it would be incompatible with your fake enums if that method return true while a different way to use them is necessary.
As your library exposes a different enum API, it should also expose a different existence function rather than reusing the PHP 8.1 name.

@stof

If a library does a enum_exists and then use the enum API based on that

How can a library using enum_exists running on < 8.1 ? and for what value ?
If it's running on >= 8.1 the native function is used.

@marc-mabe but that's the whole point of a polyfill: the library could support both PHP 8 and PHP 8.1 with the same codebase. And that's why our polyfill for enum_exists returns false all the time, because no enum (compatible with the way they are used in newer PHP versions) will ever exists in 8.0 or older.

I'm closing the issue as explained by @stof. The point of polyfill is to expose an API 100% compatible. So that application or library can use the exact same code when running on the platform using PHP 8.1 or running with the polyfill version.

How can a library using enum_exists running on < 8.1 ? and for what value ?

Hypothetical situation: VendorB provide code compatible with PHP 8.0 and PHP 8.1
VendorA deprecated code compatible with PHP8.0 in favor of new version with enum

namespace VendorA
{
  enum Worflow
  {
    case PUBLISH
  }

  /**
   * @deprecated use Workflow instead
   */
  class WorflowEvents
  {
    public const PUBLISH = 'publish';
  }
}

namespace VendorB
{
  use VendorA\Workflow;
  use VendorA\WorflowEvents;

  if (enum_exists(Worflow::class)) {
    $this->workflow->apply(Worflow::PUBLISH);
  } else {
    $this->workflow->apply(WorflowEvents::PUBLISH);
  }
}

This kind of code would work with polyfilled version of enum_exists running on PHP <8.1.

For anyone who is interested I have finished the first working version now here https://github.com/marc-mabe/php-enum-cl with the following changes by result of the discussion of this thread:

  • Don't name it polyfill but instead compatibility layer or emulated
  • Include an own version of enum_exists but on a different namespace to make sure it's being used in the correct context only

Thanks for your input 👍